This article demonstrates several approaches to implement circular printing among multiple threads in Java. The goal is to have three threads print their respective numbeers (0, 1, 2) in order, cycling through 10 times.
1. Flag Variable + Mutex Lock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
private static int sharedFlag = 0;
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while (id != sharedFlag) {
lock.unlock();
Thread.yield();
lock.lock();
}
System.out.print(id);
sharedFlag = (sharedFlag + 1) % 3;
} finally {
lock.unlock();
}
}
}
}
}
2. Flag Variable + Mutex Lock + Condition Variable
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
private static int sharedFlag = 0;
private static final Lock lock = new ReentrantLock();
private static final Condition[] conditions = new Condition[3];
public static void main(String[] args) {
conditions[0] = lock.newCondition();
conditions[1] = lock.newCondition();
conditions[2] = lock.newCondition();
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (id != sharedFlag) {
conditions[id].await();
}
System.out.print(id);
sharedFlag = (id + 1) % 3;
conditions[sharedFlag].signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
}
}
}
3. Flag Variable + synchornized
public class Main {
private static int sharedFlag = 0;
public static void main(String[] args) {
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
while (true) {
synchronized (Worker.class) {
if (id == sharedFlag) {
break;
}
}
Thread.yield();
}
System.out.print(id);
sharedFlag = (id + 1) % 3;
}
}
}
}
public class Main {
private static int sharedFlag = 0;
public static void main(String[] args) {
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (Worker.class) {
while (id != sharedFlag) {
try {
Worker.class.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print(id);
sharedFlag = (id + 1) % 3;
Worker.class.notifyAll();
}
}
}
}
}
4. Atomic Variable
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
private static final AtomicInteger sharedFlag = new AtomicInteger(0);
public static void main(String[] args) {
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
while (sharedFlag.get() != id) {
Thread.yield();
}
System.out.print(id);
sharedFlag.set((id + 1) % 3);
}
}
}
}
5. Volatile Variable
public class Main {
private static volatile int sharedFlag = 0;
public static void main(String[] args) {
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
while (sharedFlag != id) {
Thread.yield();
}
System.out.print(id);
sharedFlag = (id + 1) % 3;
}
}
}
}
6. Seamphore
import java.util.concurrent.Semaphore;
public class Main {
private static final Semaphore[] semaphores = new Semaphore[3];
public static void main(String[] args) {
semaphores[0] = new Semaphore(1);
semaphores[1] = new Semaphore(0);
semaphores[2] = new Semaphore(0);
new Thread(new Worker(0)).start();
new Thread(new Worker(1)).start();
new Thread(new Worker(2)).start();
}
private static class Worker implements Runnable {
private final int id;
Worker(int id) {
this.id = id;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
semaphores[id].acquire();
System.out.print(id);
semaphores[(id + 1) % 3].release();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
