- 方法一:synchronized + wait + notify
//三个线程循环打印数字,每个打印5个,打印数字到num
class WaitNotifyABC{
private volatile int num = 0;//线程共享变量
/**Object 和 this都可以对同步代码块加锁,但是this锁的是类的实例,如果该实例被他人拿走,
则本线程永远拿不到锁。Object也可以通过反射获取,但相比于this多一层保护。
为什么final?因为防止LOCK被重新赋值,相当于被其他线程抢走锁。*/
private static final Object LOCK = new Object();
private void printABC(int targetNum){
while(num <= 100){
synchronized(LOCK){
/*用if会造成假唤醒的问题,如果if,执行了wait之后,被唤醒了就不会再判断if条件。
while被唤醒之后会先执行while内的判断条件,避免在wait期间判断条件发生变化。*/
while(num % 3 != targetNum){
try {
LOCK.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int i = 0; i < 5; i++) {
num++;
if(num > 100){
break;
}
System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num));
}
LOCK.notifyAll();
}
}
}
public static void main(String[] args) {
WaitNotifyABC waitNotifyABC = new WaitNotifyABC();
new Thread(() -> {
waitNotifyABC.printABC(0);
},"线程A").start();
new Thread(() ->{
waitNotifyABC.printABC(2);
},"线程B").start();
new Thread(() -> {
waitNotifyABC.printABC(1);
},"线程C").start();
}
}
- 方法二:Lock
Lock方法和synchronized方法相似,对同步代码块加锁,无论哪个线程拿到锁之后都需要满足num%3 == targetNum才能执行。
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockABC { private volatile int num = 0; private Lock lock = new ReentrantLock(); private void printABC(int targetNum){ while(num <= 100){ lock.lock(); if(num % 3 == targetNum){ for (int i = 0; i < 5; i++) { num++; if(num > 100){ break; } System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num)); } } lock.unlock(); } } public static void main(String[] args) { LockABC lockABC = new LockABC(); new Thread(() -> { lockABC.printABC(0); },"线程A").start(); new Thread(() -> { lockABC.printABC(2); },"线程B").start(); new Thread(() -> { lockABC.printABC(1); },"线程C").start(); } }
- 方法三:Lock+Condition
import java.net.CacheRequest; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockCondition { private volatile int num = 0; private Lock lock = new ReentrantLock(); private Condition ca = lock.newCondition(); private Condition cb = lock.newCondition(); private Condition cc = lock.newCondition(); private void printABC(int targetNum, Condition currentThread, Condition nextThread){ while(num <= 100){ lock.lock(); try { while(num % 3 != targetNum){ if(num > 100){ break; } currentThread.await(); } for (int i = 0; i < 5; i++) { num++; if(num > 100){ break; } System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num)); } nextThread.signal(); } catch (Exception e) { e.printStackTrace(); } finally{ lock.unlock(); } } } public static void main(String[] args) { LockCondition lockCondition = new LockCondition(); new Thread(() -> { lockCondition.printABC(0, lockCondition.ca, lockCondition.cb); },"线程A").start(); new Thread(() -> { lockCondition.printABC(2, lockCondition.cb, lockCondition.cc); },"线程B").start(); new Thread(() -> { lockCondition.printABC(1, lockCondition.cc, lockCondition.ca); },"线程C").start(); } }
- 方法四:Semophore
import java.util.concurrent.Semaphore; public class SemaphoreABC { private volatile int num = 0; private Semaphore sa = new Semaphore(1); private Semaphore sb = new Semaphore(0); private Semaphore sc = new Semaphore(0); private void printABC(Semaphore currentThread, Semaphore nextThread){ while(num <= 100){ try { currentThread.acquire(); for (int i = 0; i < 5; i++) { num++; if(num > 100){ break; } System.out.println(Thread.currentThread().getName() + "-->" + String.valueOf(num)); } nextThread.release(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { SemaphoreABC semaphoreABC = new SemaphoreABC(); new Thread(() -> { semaphoreABC.printABC(semaphoreABC.sa, semaphoreABC.sb); },"线程A").start();; new Thread(() -> { semaphoreABC.printABC(semaphoreABC.sb, semaphoreABC.sc); },"线程B").start();; new Thread(() -> { semaphoreABC.printABC(semaphoreABC.sc, semaphoreABC.sa); },"线程C").start();; } }