在使用Lock之前,我们使用的最多的同步方式应该是synchronized关键字来实现同步方式了。配合Object的wait()、notify()系列方法可以实现等待/通知模式。Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式
下面用的是lock锁
首先我们需要明白condition对象是依赖于lock对象的,condition对象需要通过lock对象进行创建出来(调用Lock对象的newCondition()方法)。condition的使用需要在调用方法前获取锁。
1.传统版
- 题目:一个初始值为0的变量,两个线程一个加1一个减1,轮询5轮
-
- 线程 操作(方法) 资源类
-
- 判断 干活 通知
-
- 防止虚假唤醒机制(多线程判断用while不用if)
package JUC;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class ShareData {private int number = 0;Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void increment() throws InterruptedException {lock.lock();try {//1.判断while (number != 0) {//线程判断用while//等待不能生产condition.await();}//2.干活number++;System.out.println(Thread.currentThread().getName() + "\t" + number);//3.通知唤醒condition.signalAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void decrement() throws InterruptedException {lock.lock();try {//1.判断while (number == 0) {//线程判断用while//等待不能生产condition.await();}//2.干活number--;System.out.println(Thread.currentThread().getName() + "\t" + number);//3.通知唤醒condition.signalAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}/*** 题目:一个初始值为0的变量,两个线程一个加1一个减1,轮询5轮* <p>* 1. 线程 操作(方法) 资源类* 2. 判断 干活 通知* 3.防止虚假唤醒机制(多线程判断用while不用if)*/
public class ProdConsumer_TraditonDemo {public static void main(String[] args) {ShareData shareData = new ShareData();new Thread(() -> {for (int j = 0; j < 5; j++) {try {shareData.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "AA").start();new Thread(() -> {for (int j = 0; j < 5; j++) {try {shareData.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "BB").start();}
}
2.Condition精准唤醒( condition.signal() )
/**
- 题目:多线程之间按顺序调用,实现A->B->C三个线程启动,需求如下:
- AA打印5次,BB打印10次,CC打印15次
- 紧接着
- AA打印5次,BB打印10次,CC打印15次
- 。。。
- 。。。
- 。。。
- 来10轮
*/
package JUC;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 题目:多线程之间按顺序调用,实现A->B->C三个线程启动,需求如下:* AA打印5次,BB打印10次,CC打印15次* 紧接着* AA打印5次,BB打印10次,CC打印15次* 。。。* 。。。* 。。。* 来10轮*/class ShareResource{//资源类private int number = 1; //AA就是1,BB就是2,CC就是3private Lock lock = new ReentrantLock();private Condition c1 = lock.newCondition();private Condition c2 = lock.newCondition();private Condition c3 = lock.newCondition();//1.判断public void print5(){lock.lock();try {//1.判断while(number!=1){c1.await();}//2.干活for (int i = 1; i <= 5; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}//3.通知number = 2;c2.signal();}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}public void print10(){lock.lock();try {//1.判断while(number!=2){c2.await();}//2.干活for (int i = 1; i <= 10; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}//3.通知number = 3;c3.signal();}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}public void print15(){lock.lock();try {//1.判断while(number!=3){c3.await();}//2.干活for (int i = 1; i <= 15; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}//3.通知number = 1;c1.signal();}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}}
public class SyncAndReentrantLockDemo {public static void main(String []args){ShareResource shareResource = new ShareResource();new Thread(()->{for (int i = 1; i < 10; i++) {shareResource.print5();}},"AA").start();new Thread(()->{for (int i = 1; i < 10; i++) {shareResource.print10();}},"BB").start();new Thread(()->{for (int i = 1; i < 10; i++) {shareResource.print15();}},"CC").start();}
}
结果:只截取了一轮
AA 1
AA 2
AA 3
AA 4
AA 5
BB 1
BB 2
BB 3
BB 4
BB 5
BB 6
BB 7
BB 8
BB 9
BB 10
CC 1
CC 2
CC 3
CC 4
CC 5
CC 6
CC 7
CC 8
CC 9
CC 10
CC 11
CC 12
CC 13
CC 14
CC 15