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;
}
}






















Комментарии

Популярные сообщения из этого блога

Lesson1: JDK, JVM, JRE

SE_21_Lesson_11: Inheritance, Polymorphism

SE_21_Lesson_9: Initialization Blocks, Wrapper types, String class