题目描述
建立三个线程thread1、thread2、thread3,要求三个线程同时运行,并且实现交替打印ABC,即按照 ABCABCABCABC... 的顺序打印。
实现思路
- 使用 volatile 实现
- 使用 AtomicInteger 实现
- 使用 wait/notify 实现
- 使用 Condition 和 lock 实现
- 使用 BlockingQueue 实现
- 使用 Semaphore 实现
使用 volatile 实现
使用 volatile 实现是最容易想到的方式。
java
public class VolatileOrderThread {
static volatile int ticket = 1;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
if (ticket == 1) {
System.out.println("A");
ticket = 2;
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
if (ticket == 2) {
System.out.println("B");
ticket = 3;
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
if (ticket == 3) {
System.out.println("C");
ticket = 1;
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
使用 AtomicInteger 实现
使用 AtomicInteger 实现本质上和使用 volatile 是一回事情,在 AtomicInteger 内部也维护了一个 volatile 类型的变量,用来保证共享变量的可见性。
java
public class AtomicIntegerOrderThread {
static AtomicInteger ticket = new AtomicInteger(1);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
if (ticket.get() == 1) {
System.out.println("A");
ticket.set(2);
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
if (ticket.get() == 2) {
System.out.println("B");
ticket.set(3);
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
if (ticket.get() == 3) {
System.out.println("C");
ticket.set(1);
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
使用 wait/notify 实现
要实现线程间通信,最原始也是最万能的方法,当然是使用 wait/notify。
java
public class WaitNotifyOrderThread {
static int ticket = 1;
static final Object object = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
synchronized (object) {
try {
while (ticket != 1) {
object.wait();
}
System.out.println("A");
ticket = 2;
object.notifyAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
synchronized (object) {
try {
while (ticket != 2) {
object.wait();
}
System.out.println("B");
ticket = 3;
object.notifyAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
synchronized (object) {
try {
while (ticket != 3) {
object.wait();
}
System.out.println("C");
ticket = 1;
object.notifyAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
使用 Condition 和 lock 实现
Doug Lea 神一样的男人。
java
public class ConditionOrderThread {
static int ticket = 1;
static Lock lock = new ReentrantLock();
static Condition conditionA = lock.newCondition();
static Condition conditionB = lock.newCondition();
static Condition conditionC = lock.newCondition();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
lock.lock();
try {
if (ticket != 1) {
conditionA.await();
}
System.out.println("A");
ticket = 2;
conditionB.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
lock.lock();
try {
if (ticket != 2) {
conditionB.await();
}
System.out.println("B");
ticket = 3;
conditionC.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
lock.lock();
try {
if (ticket != 3) {
conditionC.await();
}
System.out.println("C");
ticket = 1;
conditionA.signal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
使用 BlockingQueue 实现
这种方式,本质上也是使用 Condition 和 lock,阻塞队列的 take 方法就是使用 Condition 和 lock 实现的。
java
public class BlockingQueueOrderThread {
static BlockingQueue<Character> queueA = new LinkedBlockingQueue<>(1);
static BlockingQueue<Character> queueB = new LinkedBlockingQueue<>(1);
static BlockingQueue<Character> queueC = new LinkedBlockingQueue<>(1);
public static void main(String[] args) {
queueA.add('A');
Thread thread1 = new Thread(() -> {
while (true) {
try {
Character element = queueA.take();
System.out.println(element);
queueB.put('B');
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
try {
Character element = queueB.take();
System.out.println(element);
queueC.put('c');
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
try {
Character element = queueC.take();
System.out.println(element);
queueA.put('A');
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
使用 Semaphore 实现
使用 基于 AQS 的 Semaphore(信号量) 也可以轻松的实现。
java
public class SemaphoreOrderThread {
static Semaphore semaphoreA = new Semaphore(1);
static Semaphore semaphoreB = new Semaphore(0);
static Semaphore semaphoreC = new Semaphore(0);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
try {
semaphoreA.acquire();
System.out.println("A");
semaphoreB.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
try {
semaphoreB.acquire();
System.out.println("B");
semaphoreC.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread thread3 = new Thread(() -> {
while (true) {
try {
semaphoreC.acquire();
System.out.println("C");
semaphoreA.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread1.start();
thread2.start();
thread3.start();
}
}
总结
虽然有多种方法,但归根结底只有两种:
- 一种是基于 Java 原生的锁机制;
- 一种是基于 CAS 的锁机制