在使用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就是3
private 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