thread-线程之间通讯wait,notify,notifyAll

jstack查看死锁

多个线程共同去抢多个锁的时候,容易出现死锁,通过jstack命令可以查看死锁。

jstack pid

线程通讯

wait,notify, nofityAll是和同步synchronized一同使用的, wait的意思就是当前线程放弃了这个锁

单生产者消费者

public class SimpleProducerAndConsumer {
    
    private final Object LOCK = new Object();

    // 生产和消费的数据
    private Integer index = 0;

    // 判断生产状态
    private volatile boolean isProduced = false;


    public void produce(){
        synchronized(LOCK){
            if(isProduced){
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                index++;
                System.out.println("P->" + index);
                LOCK.notify();
                isProduced = true;
            }
        }
    }

    public void consume(){
        synchronized(LOCK){
            if(isProduced){
                System.out.println("C->" + index);
                LOCK.notify();
                isProduced = false;
            }else{
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SimpleProducerAndConsumer simple = new SimpleProducerAndConsumer();

        new Thread(() -> {
            while (true) {
                simple.produce();
            }
        }).start();

        new Thread(() -> {
            while (true) {
                simple.consume();
            }
        }).start();
    }
}

多生产者消费者

notify是唤醒除了此线程之外的其他所有线程的任意一个, 如果多个生产者多个消费者,消费者可能会唤醒另外一个消费者, 结果最后生产者消费者都wait住了,就会出现假死现象,多个生产者消费者要用notifyAll, 会唤醒所有wait的线程

import java.util.stream.Stream;

public class SimpleProducerAndConsumer {

    private final Object LOCK = new Object();

    // 生产和消费的数据
    private Integer index = 0;

    // 判断生产状态
    private volatile boolean isProduced = false;

    public void produce() {
        synchronized (LOCK) {
            if (isProduced) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                index++;
                System.out.println(Thread.currentThread().getName() + "---------------------------------------------->" + index);
                LOCK.notifyAll();
                isProduced = true;
            }
        }
    }

    public void consume() {
        synchronized (LOCK) {
            if (isProduced) {
                System.out.println(Thread.currentThread().getName() + "->" + index);
                LOCK.notifyAll();
                isProduced = false;
            } else {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SimpleProducerAndConsumer simple = new SimpleProducerAndConsumer();

        Stream.of("P1", "P2", "P3", "P4").forEach(n -> new Thread(() -> {
            while (true) {
                simple.produce();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, n).start());

        Stream.of("C1", "C2", "C3").forEach(n -> new Thread(() -> {
            while (true) {
                simple.consume();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, n).start());
    }
}

wait set

  1. 每个对象都有wait set的概念, 存放该对象wait方法之后进入block状态的线程
  2. 线程notify之后进入runnable状态, 并不一定立即执行
  3. 线程从wait set中被唤醒顺序是不确定的
  4. 线程被唤醒后, 会重新获取锁, 代码从wait后面开始执行
package com.mine;

import java.util.Optional;
import java.util.stream.IntStream;

public class WaitSet {

  private static final Object LOCK = new Object();
  
  public static void main(String[] args) {
    IntStream.rangeClosed(1, 10).forEach(i -> 
      new Thread(() -> {
        synchronized(LOCK){
          Optional.of(Thread.currentThread().getName() + " 进入wait set").ifPresent(System.out::println);
          try {
            LOCK.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          Optional.of(Thread.currentThread().getName() + " 离开wait set").ifPresent(System.out::println);

        }
      }, String.valueOf(i)).start()
    );

    try {
      Thread.sleep(10_000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    // 一个一个的唤醒线程
    synchronized(LOCK){
      IntStream.rangeClosed(1, 10).forEach(
        i -> LOCK.notify()
      );
    }
  }
}

输出结果为:

2 进入wait set
10 进入wait set
9 进入wait set
8 进入wait set
7 进入wait set
6 进入wait set
4 进入wait set
5 进入wait set
3 进入wait set
1 进入wait set

2 离开wait set
1 离开wait set
3 离开wait set
5 离开wait set
4 离开wait set
6 离开wait set
7 离开wait set
8 离开wait set
9 离开wait set
10 离开wait set

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值