Java线程通信--假死问题

死锁和阻塞的区别:

死锁:是由于两个对象在拥有一份资源的情况下申请另一份资源,而另一份资源恰好又是这两个对象所持有的,导致两个对象无法完成操作,且所持资源无法释放。

阻塞:是由于资源不足引起的排队等待的现象。

“假死”的现象就是全部线程都进入了WAITING状态(死锁),则程序就不再执行任何业务功能了,整个项目呈停止状态。

这里以常见的生产者消费者模型分析:
import lombok.SneakyThrows;

public class ProduceConsumerSync {
    //定义变量
    private int i = 0;
    //定义一把锁
    final private Object lock = new Object();
    //判断状态
    private volatile boolean isProduced = false;

    //生产者
    public void Produce() throws InterruptedException {
        synchronized (lock) {
            //如果已经生产了,就等待消费
            if (isProduced) {
                lock.wait();
            } else {  //如果没有生产,就直接生产,通知消费者继续消费
                i++; //生产
                System.out.println(Thread.currentThread().getName() + "Produce生产者生产消息" + i);
                lock.notify();
                isProduced = true;
            }
        }
    }

    //消费者
    public void Consumer() throws InterruptedException {
        synchronized (lock) {
            //如果已经有生产,就直接消费,并通知生产者继续生产
            if (isProduced) {
                System.out.println(Thread.currentThread().getName() + "Consumer消费者消费消息" + i);
                lock.notify();
                isProduced = false;
            } else {
                lock.wait();
            }
        }
    }

    public static void main(String[] args) {
        ProduceConsumerSync model = new ProduceConsumerSync();

		//生产者不停生产消息
        for (int i = 0; i < 10; i++) {
            new Thread() {
                @SneakyThrows
                @Override
                public void run() {
                    while (true) {
                        model.Produce();
                    }
                }
            }.start();
        }
		//消费者不停消费消息
        for (int i = 0; i < 10; i++) {
            new Thread() {
                @SneakyThrows
                @Override
                public void run() {
                    while (true) {
                        model.Consumer();
                    }
                }
            }.start();
        }
    }
}

在这里插入图片描述
本来整个程序是永不停歇的,但是在生产了6个产品之后,突然间就停歇了,多线程通信出现了假死状态。
原因:notify通知的是是同类。造成了这种堵塞现象。

使用jstack和jconsole查看线程状态信息

  • 使用jps查看当前电脑存在的所有java线程
  • 使用jstack工具查看线程状态信息
    在这里插入图片描述
    目前所有的线程都是处于等待的状态,这也就是假死现象的验证。
  • 使用jconsole图形分析线程
    在这里插入图片描述
    在这里插入图片描述
    查看到所有线程都处于阻塞状态,定位到阻塞产生原因。

总结

notify()只唤醒一个正在等待的线程,当该线程执行完以后释放该对象的锁,而没有再次执行notify()方法,则其它正在等待的线程,一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池,就会发生死锁。
notify和notifyAll的区别:

  • notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
  • void notify(): 唤醒一个正在等待该对象的线程。
  • void notifyAll(): 唤醒所有正在等待该对象的线程。
两者的最大区别在于:
     notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
     notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。 

解决方案

ReentrantLock
notifyAll
(有待完善)…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值