纵向对比:
synchronized wait() notifyAll()
| | |
ReentrantLock condition.await() condition.signalAll()
实例对比:
题目:四个人控制一个空调开关,两个人控制开,两个人控制关,需要开关交替进行。
package main.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Auther: wdq
* @Date: 2020/4/19 15:53
* @Description:
*/
/*
class AirConditioner {
private int number = 0;
public synchronized void increament() throws InterruptedException {
//wait
while (number==1){
this.wait();
}
//work
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
//wait
while (number==0){
this.wait();
}
//work
number--;
System.out.println(Thread.currentThread().getName()+"\t"+number);
this.notifyAll();
}
}
*/
class AirConditioner {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increament() throws InterruptedException {
lock.lock();
try {
//判断
while(number == 1){
condition.await();
}
//干活
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
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 threadWaitNotify {
public static void main(String[] args) {
AirConditioner airConditioner = new AirConditioner();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
airConditioner.increament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
airConditioner.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
airConditioner.increament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"C").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
airConditioner.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"D").start();
}
}
lock相对的优势就是配合condition用,达到精准唤醒的效果
题目:
多线程之间按顺序调用,实现A->B-C
三个线程启动,要求如下:
A打印5次,B打印10次,C打印15次;
接着
A打印5次,B打印10次,C打印15次;
。。。循环10轮。
package main.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Auther: wdq
* @Date: 2020/4/19 18:36
* @Description:
*/
class ShareResource {
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void print5(){
lock.lock();
try {
//判断
while (number != 1){
condition1.await();
}
//干活
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
//通知
number = 2;
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print10(){
lock.lock();
try {
//判断
while (number != 2){
condition2.await();
}
//干活
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
//通知
number = 3;
condition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print15(){
lock.lock();
try {
//判断
while (number != 3){
condition3.await();
}
//干活
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
//通知
number = 1;
condition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class ThreadOrderAccess {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print5();
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print10();
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print15();
}
},"C").start();
}
}
多线程编程结论:
1、高聚低合前提下,线程操作资源类
2、判断/干活/通知
3、多线程交互中,必须要防止多线程的虚假唤醒,也即(判断只用while,不能用if)
4、标记位