public class printDemo04 {
public static void main(String[] args) {
Resource01 resource01 = new Resource01();
Producer producer = new Producer(resource01);
Producers producers = new Producers(resource01);
Thread thread0 = new Thread(producer);
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(producers);
Thread thread3 = new Thread(producers);
thread0.start();
thread1.start();
thread2.start();
thread3.start();
}
}
class Resource01{
private String name;
private int sex = 1;
private boolean flag = false;
public synchronized void setSth(String name){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+sex;
sex++;
System.out.println(Thread.currentThread().getName()+"----"+"生产者..."+this.name);
flag = true;
this.notifyAll();
} public synchronized void getSth(){
while(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--"+"消费者..."+name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
Resource01 resource01;
public Producer(Resource01 resource01) {
this.resource01 = resource01;
}
int i = 1;
@Override
public void run() {
while(true){
if(i==1){
resource01.setSth("烤鸭");
}
i = (i+1)%2;
}
}
}
class Producers implements Runnable{
Resource01 resource01;
public Producers(Resource01 resource01) {
this.resource01 = resource01;
} @Override
public void run() {
while(true){
resource01.getSth();
}
}
}

  死锁发生的情况:上述代码中,把标色的this.notifyAll();改为this.notify();就会发生线程的死锁,为什么呢?应为代码中总共有4个线程,生产者1和生产者2,消费者1和消费者2。理想状态是生产者1和生产者2执行生产操作,消费者1和消费者2执行消费操作,生产一个,消费一个。现在线程进入首先执行生产操作,打个比方生产1生产了烤鸭1,然后flag等于true,如果接下来执行的生产操作的话,这个生产线程就会被等待,这时候执行的生产者2,就会被等待,接下来执行消费者2线程消费者2线程执行完以后flag为false,这时候有要选择一个线程执行,因为生产者2在线程池中被等待,所以现在只能执行生产者1、消费者1和消费者2,假设这时候执行生产者1又生产了烤鸭2,然后又在前面三个线程中选择了生产者1,这时候flag为true,生产者1又进入了线程池进行了等待。然后线程只有2个可以执行消费者1和消费者2,这时候消费完以后,flag为false,接下来只能执行消费线程,但是没法生产flag就只能为false,所以这时候消费者1和消费者2就都会被等待,到此为止,4个线程都被等待,于是就发生了死锁。使用notifyAll()就不会发生死锁了。

  while在这的作用是判断当前执行的线程是否应该被执行,就像代码中所表示的执行完生产只能消费。

线程死锁情况和while在线程的作用的更多相关文章

  1. .NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长

    一个 asp.net core 站点,之前运行在Linux 服务器上,运行一段时间后有时站点会挂掉,在日志中记录很多“EMFILE too many open files”的错误: Microsoft ...

  2. 并发编程-线程-死锁现象-GIL全局锁-线程池

    一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...

  3. 尝试解决在构造函数中同步调用Dns.GetHostAddressesAsync()引起的线程死锁

    (最终采用的是方法4) 问题详情见:.NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长 看看在 Linux 与 Windows 上发生线程死锁的后果. Linux: Microsoft ...

  4. .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法

    1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...

  5. 55行代码实现Java线程死锁

    死锁是Java多线程的重要概念之一,也经常出现在各大公司的笔试面试之中.那么如何创造出一个简单的死锁情况?请看代码: class Test implements Runnable { boolean ...

  6. 对象及变量的并发访问(同步方法、同步代码块、对class进行加锁、线程死锁)&内部类的基本用法

    主要学习多线程的并发访问,也就是使得线程安全. 同步的单词为synchronized,异步的单词为asynchronized 同步主要就是通过锁的方式实现,一种就是隐式锁,另一种是显示锁Lock,本节 ...

  7. java命令分析线程死锁以及内存泄漏

    一.介绍 jstack是java虚拟机自带的一种堆栈跟踪工具.jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项&qu ...

  8. Python并发编程-进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  9. Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript.

    Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript. 1. 现象::主程序卡住无反应,多行任务不往下执行 1 2. 原因::使用j ...

随机推荐

  1. dataWithContentsOfURL报错问题

    NSError *error = nil; NSData* videoData = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.re ...

  2. [NOIP2011] 计算系数(二项式定理)

    题目描述 给定一个多项式(by+ax)^k,请求出多项式展开后x^n*y^m 项的系数. 输入输出格式 输入格式: 输入文件名为factor.in. 共一行,包含5 个整数,分别为 a ,b ,k , ...

  3. error LNK2005: _DllMain@12 已经在 dllmain.obj 中定义

    error LNK2005: _DllMain@ 已经在 dllmain.obj 中定义 今天遇到了同样的问题,搜索搜到了这里,后来解决了........ 创建解决方案时,用的是WIN32 DLL,添 ...

  4. struts2 的验证框架validation如何返回json数据 以方便ajax交互

    struts2 的验证框架validation简单,好用,但是input只能输出到jsp页面通过struts2的标签<s:fielderror  />才能取出,(EL应该也可以). 如果使 ...

  5. import logging 导入记录日志包

    import logging 日志几个级别 logging.debug logging.info logging.error

  6. Node.js网络编程

    Node.js为javascript语言提供了一个在服务端运行的平台,它以其事件驱动,非阻塞I/O机制使得它本身非常适合开发运行在在分布式设备上的I/O密集型应用,分布式应用要求Node.js必须对网 ...

  7. FullCalendar只可以从外部拖入,内部不能互相拖动

    startDrag: function(ev) { if(ev.originalEvent.initEvent){ return; } if (!this.isListening) { // star ...

  8. 建立一个简单的SpringMVC程序

    首先,所建立的程序是一个web程序,所以在web.xml文件中进行如下的配置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ...

  9. PostMessager来对子父窗体进行跨域

    一.为什么需要使用postMessage这个跨域技术 对于一个普通的页面而言,如果页面中的数据量太多时,会导致某个页面的数据量太多 二显得特别的臃肿,所以通常是使用iframe的方式来加载子页面,但是 ...

  10. Chapter6: question 43 - 45

    43.  投 n 个骰子,计算点数和出现的概率 递归求解:(空间 O(5*n+1),时间 O(6n)) void count(int N, int curN, int sum, int record[ ...