MultiThreading
Multithreading in Java refers to the concurrent execution of multiple threads within a java program. A thread is a lightweight sub-process, and multithreading allows you to perform multiple tasks simultaneously, improving the overall efficiency of your program.
Thread basics:
package test;
public class Main {
public static void main(String[] args) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getClass().getName());
printThreadState(currentThread);
}
public static void printThreadState(Thread thread) {
System.out.println("--------------------------------------------");
System.out.println("Thread ID: " + thread.getId());
System.out.println("Thread Name: " + thread.getName());
System.out.println("Thread Priority:" + thread.getPriority());
System.out.println("Thread State: " + thread.getState());
System.out.println("Thread Group:" + thread.getThreadGroup());
System.out.println("Thread Is Alive: " + thread.isAlive());
System.out.println("--------------------------------------------");
}
}
package thread;
public class CustomThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.print(" 1 ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package thread;
public class Main {
public static void main(String[] args) {
CustomThread thread = new CustomThread();
thread.run();
for(int i = 0; i < 5; i++) {
System.out.print(" 0 ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Interacting with a running thread:
package thread;
public class Main {
public static void main(String[] args) {
System.out.println("Main Thread running");
try {
System.out.println("Main Thread paused for one second");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = new Thread(() -> {
String tname = Thread.currentThread().getName();
System.out.println(tname + " should take 10 dots to run.");
for (int i = 0; i < 10; i++) {
System.out.print(". ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("\nWhoops!! " + tname + " interrupted.");
return;
}
}
System.out.println("\n" + tname + " completed.");
});
System.out.println(thread.getName() + " starting");
thread.start();
System.out.println("Main Thread would continue here");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
package thread;
public class Main {
public static void main(String[] args) {
System.out.println("Main Thread running : " + Thread.currentThread().getName());
try {
System.out.println("Main Thread paused for one second");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = new Thread(() -> {
String tname = Thread.currentThread().getName();
System.out.println(tname + " should take 10 dots to run.");
for (int i = 0; i < 10; i++) {
System.out.print(". ");
try {
Thread.sleep(500);
System.out.println("A. State = " + Thread.currentThread().getState());
} catch (InterruptedException e) {
System.out.println("\nWhoops!! " + tname + " interrupted.");
System.out.println("A1. State = " + Thread.currentThread().getState());
return;
}
}
System.out.println("\n" + tname + " completed.");
});
System.out.println(thread.getName() + " starting");
thread.start();
long now = System.currentTimeMillis();
while (thread.isAlive()) {
System.out.println("\nwaiting for thread to complete");
try {
Thread.sleep(1000);
System.out.println("B. State = " + thread.getState());
if (System.currentTimeMillis() - now > 2000) {
thread.interrupt();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("C. State = " + thread.getState());
// System.out.println("Main Thread would continue here");
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// thread.interrupt();
}
}
package thread;
public class Main {
public static void main(String[] args) {
System.out.println("Main Thread running : " + Thread.currentThread().getName());
try {
System.out.println("Main Thread paused for one second");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = new Thread(() -> {
String tname = Thread.currentThread().getName();
System.out.println(tname + " should take 10 dots to run.");
for (int i = 0; i < 10; i++) {
System.out.print(". ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("\nWhoops!! " + tname + " interrupted.");
return;
}
}
System.out.println("\n" + tname + " completed.");
});
Thread installThread = new Thread(() -> {
try {
for (int i = 0; i < 3; i++) {
Thread.sleep(1000);
System.out.println("Installation Step " + (i + 1) + " is completed.");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "InstallThread");
Thread threadMonitor = new Thread(() -> {
long now = System.currentTimeMillis();
while (thread.isAlive()) {
try {
Thread.sleep(1000);
if (System.currentTimeMillis() - now > 2000) {
thread.interrupt();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println(thread.getName() + " starting");
thread.start();
threadMonitor.start();
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!thread.isInterrupted()) {
installThread.start();
} else {
System.out.println("Previous thread was interrupted, " +
installThread.getName() + " can't run.");
}
}
}
package thread;
public class Main {
public static void main(String[] args) {
System.out.println("Main Thread running : " + Thread.currentThread().getName());
try {
System.out.println("Main Thread paused for one second");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = new Thread(() -> {
String tname = Thread.currentThread().getName();
System.out.println(tname + " should take 10 dots to run.");
for (int i = 0; i < 10; i++) {
System.out.print(". ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("\nWhoops!! " + tname + " interrupted.");
Thread.currentThread().interrupt();
return;
}
}
System.out.println("\n" + tname + " completed.");
});
Thread installThread = new Thread(() -> {
try {
for (int i = 0; i < 3; i++) {
Thread.sleep(1000);
System.out.println("Installation Step " + (i + 1) + " is completed.");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "InstallThread");
Thread threadMonitor = new Thread(() -> {
long now = System.currentTimeMillis();
while (thread.isAlive()) {
try {
Thread.sleep(1000);
if (System.currentTimeMillis() - now > 2000) {
thread.interrupt();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println(thread.getName() + " starting");
thread.start();
threadMonitor.start();
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!thread.isInterrupted()) {
installThread.start();
} else {
System.out.println("Previous thread was interrupted, " +
installThread.getName() + " can't run.");
}
}
}
Concurrent Thread concepts:
package main;
import java.util.concurrent.TimeUnit;
public class CachedData {
private boolean flag = false;
public void toggleFlag() {
flag = !flag;
}
public boolean isReady() {
return flag;
}
public static void main(String[] args) {
CachedData example = new CachedData();
Thread writerThread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
example.toggleFlag();
System.out.println("A. Flag set to " + example.isReady());
});
Thread readerThread = new Thread(() -> {
while (!example.isReady()) {
// Busy-wait until flag becomes true
}
System.out.println("B. Flag is " + example.isReady());
});
writerThread.start();
readerThread.start();
}
}
Volatile:
package main;
import java.util.concurrent.TimeUnit;
public class CachedData {
private volatile boolean flag = false;
public void toggleFlag() {
flag = !flag;
}
public boolean isReady() {
return flag;
}
public static void main(String[] args) {
CachedData example = new CachedData();
Thread writerThread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
example.toggleFlag();
System.out.println("A. Flag set to " + example.isReady());
});
Thread readerThread = new Thread(() -> {
while (!example.isReady()) {
// Busy-wait until flag becomes true
}
System.out.println("B. Flag is " + example.isReady());
});
writerThread.start();
readerThread.start();
}
}
Synchronization:
package main;
public class BankAccount {
private volatile double balance;
public BankAccount(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public synchronized void deposit(double amount) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
double originalBalance = balance;
balance += amount;
System.out.printf("STARTING BALANCE: %.0f, DEPOSIT (%.0f)" +
" : NEW BALANCE = %.0f%n", originalBalance, amount, balance);
}
public synchronized void withdraw(double amount) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
double originalBalance = balance;
if (amount <= balance) {
balance -= amount;
System.out.printf("STARTING BALANCE: %.0f, WITHDRAWAL (%.0f)" +
" : NEW BALANCE = %.0f%n", originalBalance, amount, balance);
} else {
System.out.printf("STARTING BALANCE: %.0f, WITHDRAWAL (%.0f)" +
" : INSUFFICIENT FUNDS!", originalBalance, amount);
}
}
}
package main;
import java.util.concurrent.TimeUnit;
public class Task {
public static void main(String[] args) throws InterruptedException {
BankAccount bankAccount = new BankAccount(10000);
Thread thread1 = new Thread(() -> bankAccount.withdraw(2500));
Thread thread2 = new Thread(() -> bankAccount.deposit(5000));
Thread thread3 = new Thread(() -> bankAccount.withdraw(2500));
thread1.start();
thread2.start();
thread3.start();
try {
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final balance: " + bankAccount.getBalance());
}
}
another example:
package main;
public class BankAccount {
private volatile double balance;
public BankAccount(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
double originalBalance = balance;
balance += amount;
System.out.printf("STARTING BALANCE: %.0f, DEPOSIT (%.0f)" +
" : NEW BALANCE = %.0f%n", originalBalance, amount, balance);
}
}
public synchronized void withdraw(double amount) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
double originalBalance = balance;
if (amount <= balance) {
balance -= amount;
System.out.printf("STARTING BALANCE: %.0f, WITHDRAWAL (%.0f)" +
" : NEW BALANCE = %.0f%n", originalBalance, amount, balance);
} else {
System.out.printf("STARTING BALANCE: %.0f, WITHDRAWAL (%.0f)" +
" : INSUFFICIENT FUNDS!", originalBalance, amount);
}
}
}
Deadlock:
package main;
import java.util.Random;
class MessageRepository {
private String message;
private boolean hasMessage = false;
public synchronized String read() {
while (!hasMessage) {
}
hasMessage = false;
return message;
}
public synchronized void write(String message) {
while (hasMessage) {
}
hasMessage = true;
this.message = message;
}
}
class MessageWriter implements Runnable {
private MessageRepository outgoingMessage;
private final String text = """
Humpty Dumpty sat on wall,
Humpty Dumpty had a great fall,
All the king's horses and all the king's men,
Couldn't put Humpty together again.""";
public MessageWriter(MessageRepository outgoingMessage) {
this.outgoingMessage = outgoingMessage;
}
@Override
public void run() {
Random random = new Random();
String[] lines = text.split("\n");
for (int i = 0; i < lines.length; i++) {
outgoingMessage.write(lines[i]);
try {
Thread.sleep(random.nextInt(500, 2000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
outgoingMessage.write("Finished");
}
}
class MessageReader implements Runnable {
private MessageRepository incomingMessage;
public MessageReader(MessageRepository outgoingMessage) {
this.incomingMessage = outgoingMessage;
}
@Override
public void run() {
Random random = new Random();
String lastMessage = "";
do {
try {
Thread.sleep(random.nextInt(500, 2000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
lastMessage = incomingMessage.read();
System.out.println(lastMessage);
} while (!lastMessage.equals("Finished"));
}
}
public class Task {
public static void main(String[] args) throws InterruptedException {
MessageRepository repository = new MessageRepository();
Thread reader = new Thread(new MessageReader(repository));
Thread write = new Thread(new MessageWriter(repository));
reader.start();
write.start();
}
}
===========================================================================
Volatile:
package scheduler;
public class VolatileMain {
volatile static int i;
public static void main(String[] args) {
new MyThreadWrite().start();
new MyThreadRead().start();
}
static class MyThreadWrite extends Thread {
@Override
public void run() {
while (i < 5) {
System.out.println("increment i to " + (++i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
static class MyThreadRead extends Thread {
@Override
public void run() {
int localVar = i;
while (localVar < 5) {
if (localVar != i) {
System.out.println("localVar is " + localVar);
System.out.println("New value of i is " + i);
localVar = i;
}
}
}
}
}
Atomic:
package scheduler;
import java.util.concurrent.atomic.AtomicInteger;
public class VolatileMain {
static AtomicInteger i = new AtomicInteger(0);
static int k;
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j < 10_000; j++) {
new MyThread().start();
}
// Thread.sleep(2000);
System.out.println(i);
System.out.println(k);
}
static class MyThread extends Thread {
@Override
public void run() {
k++;
i.incrementAndGet();
}
}
}
Deadlock:
package threads;
public class Main {
public static void main(String[] args) {
ResourceA resourceA = new ResourceA();
ResourceB resourceB = new ResourceB();
resourceA.resourceB = resourceB;
resourceB.resourceA = resourceA;
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.resourceA = resourceA;
thread2.resourceB = resourceB;
thread1.start();
thread2.start();
}
}
class Thread1 extends Thread {
ResourceA resourceA;
@Override
public void run() {
System.out.println(resourceA.getI());
}
}
class Thread2 extends Thread {
ResourceB resourceB;
@Override
public void run() {
System.out.println(resourceB.getI());
}
}
class ResourceA {
ResourceB resourceB;
public synchronized int getI() {
return resourceB.returnI();
}
public synchronized int returnI() {
return 1;
}
}
class ResourceB {
ResourceA resourceA;
public synchronized int getI() {
return resourceA.returnI();
}
public synchronized int returnI() {
return 2;
}
}
Wait and notify:
package threads;
public class Main {
public static void main(String[] args) {
ResourceA resourceA = new ResourceA();
ResourceB resourceB = new ResourceB();
resourceA.resourceB = resourceB;
resourceB.resourceA = resourceA;
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.resourceA = resourceA;
thread2.resourceB = resourceB;
thread1.start();
thread2.start();
}
}
class Thread1 extends Thread {
ResourceA resourceA;
@Override
public void run() {
System.out.println(resourceA.getI());
}
}
class Thread2 extends Thread {
ResourceB resourceB;
@Override
public void run() {
System.out.println(resourceB.getI());
}
}
class ResourceA {
ResourceB resourceB;
public synchronized int getI() {
return resourceB.returnI();
}
public synchronized int returnI() {
return 1;
}
}
class ResourceB {
ResourceA resourceA;
public synchronized int getI() {
return resourceA.returnI();
}
public synchronized int returnI() {
return 2;
}
}
Комментарии
Отправить комментарий