使用synchronized版本:
class ShareResource {
private int number = 0;
public synchronized void up() {
//判断
while(number != 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//干活
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
this.notifyAll();
}
public synchronized void down() {
//判断
while (number == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
this.notifyAll();
}
}
public class Test {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.up();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.down();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.up();
}
}, "CCC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.down();
}
}, "DDD").start();
}
}
注意多线程的判断需要使用while,不能使用if,主要为了防止虚假唤醒
使用ReentrantLock版本
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void up() {
lock.lock();
try{
//判断
while(number != 0) {
condition.await();
}
//干活
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void down() {
lock.lock();
try{
//判断
while(number == 0) {
condition.await();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.up();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.down();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.up();
}
}, "CCC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.down();
}
}, "DDD").start();
}
}
在这两块代码似乎synchronized与lock没有区别,但是如果我们现在的需求变成:
多个线程之间的调用顺序,实现A->B->C:
三个线程的启动顺序如下:
AA打印5次,BB打印10次,CC打印15次,…持续10轮。
在这个需求中,就需要多个线程执行时有一定的顺序可依,如果使用signalAll,默认是全部唤醒,signal是随机唤醒,都无法实现准确唤醒某线程,所以需要对代码做一下改变:
//根据需求创建三把锁
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void print5() {
lock.lock();
try {
//判断
while(number != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//干活
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName()+"\t"+ i);
}
//先变更标识位
number = 2;
//通知
//精确通知带被锁2阻塞的线程
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}