「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」 1.高聚合低内聚前提下,线程操作资源类
2.判断/干活/通知
3.多线程交互中,必须要防止多线程的虚假唤醒
多线程交互中不能用if必须用while
虚假唤醒
像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
} 该方法只能由作为该对象的监视器的所有者的线程调用。 有关线程可以成为监视器所有者的方式的说明,请参阅notify方法。
买票的程序没有交互
蛋糕店卖蛋糕有需求才制作
wait释放锁,sleep不释放锁
使用while替代if防止虚假唤醒
package com.lemon;
public class Lesson2_Producter {
public static void main(String[] args) {
AirConditioner airConditioner = new AirConditioner();
new Thread(()->{
for (int i = 0; i <100 ; i++) {
try {
airConditioner.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <100 ; i++) {
try {
airConditioner.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i <100 ; i++) {
try {
airConditioner.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
//线程D
new Thread(()->{
for (int i = 0; i <100 ; i++) {
try {
airConditioner.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class AirConditioner{
private int num=0;
public synchronized void increment() throws InterruptedException {
while(num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+" num="+num);
this.notifyAll();//通知其他线程
}
public synchronized void decrement() throws InterruptedException {
while(num!=1){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+" num="+num);
this.notifyAll();
}
}
等待时间越长优先级越高
使用lock
//新的方式实现 lock
class AirConditionerLock {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int num = 0;
public void increment() {
lock.lock();
try {
while (num != 0) {
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName() + " num=" + num);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
2.通知顺序访问
可重入锁
下订单 减库存 调用支付
打印5次A,10次B,2次C循环打印,精确唤醒
package com.lemon;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Lesson3_AccurateNotify {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(()->{
for (int i = 0; i <5 ; i++) {
shareResource.print5();
}
},"A").start();
new Thread(()->{
for (int i = 0; i <5 ; i++) {
shareResource.print10();
}
},"B").start();
new Thread(()->{
for (int i = 0; i <5 ; i++) {
shareResource.print2();
}
},"C").start();
}
}
class ShareResource{
private int number =1; //标志位 1 2 3
Lock lock=new ReentrantLock();
Condition condition1=lock.newCondition();
Condition condition2=lock.newCondition();
Condition condition3=lock.newCondition();
public void print5(){
lock.lock();
try{
while(number!=1){ //1.判断
condition1.await();
}
for (int i = 0; i <5 ; i++) { //2.干活
System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
}
//3.通知
number=2; //改变标志位
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print10(){
lock.lock();
try{
while(number!=2){ //1.判断
condition2.await();
}
for (int i = 0; i <10 ; i++) { //2.干活
System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
}
//3.通知
number=3; //改变标志位
condition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print2(){
lock.lock();
try{
while(number!=3){ //1.判断
condition3.await();
}
for (int i = 0; i <2 ; i++) { //2.干活
System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
}
//3.通知
number=1; //改变标志位
condition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}