Java编程之多线程死锁与线程间通信简单实现代码

 更新时间:2017年10月26日 14:09:05   作者:yongxiHU  
这篇文章主要介绍了Java编程之多线程死锁与线程间通信简单实现代码,具有一定参考价值,需要的朋友可以了解下。

死锁定义

死锁是指两个或者多个线程被永久阻塞的一种局面,产生的前提是要有两个或两个以上的线程,并且来操作两个或者多个以上的共同资源;我的理解是用两个线程来举例,现有线程A和B同时操作两个共同资源a和b,A操作a的时候上锁LockA,继续执行的时候,A还需要LockB进行下面的操作,这个时候b资源在被B线程操作,刚好被上了锁LockB,假如此时线程B刚好释放了LockB则没有问题,但没有释放LockB锁的时候,线程A和B形成了对LockB锁资源的争夺,从而造成阻塞,形成死锁;具体其死锁代码如下:

public class MyDeadLockTest {
 public static void main(String[] args){
  Object obj1 = new Object();
  Thread thread1 = new Thread(new DeadRes(true,obj1));
  Thread thread2 = new Thread(new DeadRes(false,obj1));
  thread1.start();
  thread2.start();
 }
}
class DeadRes implements Runnable{
 boolean flag;
 Object obj;
 public DeadRes(boolean flag, Object obj1) {
  this.flag = flag;
  this.obj = obj1;
 }
 @Override
 public void run() {
   if(flag){
    synchronized (DeadRes.class){
     System.out.println(Thread.currentThread().getName()+" acquie lock is DeadRes.class");
     synchronized (obj){
      System.out.println(Thread.currentThread().getName()+" acquie lock is obj");
     }
    }
   }else{
    synchronized (obj){
     System.out.println(Thread.currentThread().getName()+" acquie lock is obj");
     synchronized (DeadRes.class){
      System.out.println(Thread.currentThread().getName()+" acquie lock is DeadRes.class");
     }
    }
   }
 }
}

执行结果如下图:

Thread-1 acquie lock is obj
Thread-0 acquie lock is DeadRes.class

当然每次执行的结果不一样,有可能是一种和谐状态,没有发生死锁,此时为保证每次死锁,可以让run()方法中,执行while(true)循环,这样保证了每次必定发生死锁;当然实际应用中,我们应该尽量避免死锁,当有多线程操作多个共同资源的时候,避免发生同一锁对象的同步嵌套。

线程间的通讯—-生产者与消费者模式

1、让两个线程交替进行操作,当生产了一个数字后,紧接着消费一个,首先采用Object对象中的wait-notify来实现,具体代码如下:

public class ThreadProConsume {
 public static void main(String[] args){
  Product product = new Product();
  Thread thread1 = new Thread(new Producer(product));
  Thread thread2 = new Thread(new Consumer(product));
  thread1.start();
  thread2.start();
 }
}
class Product{
 String name;
 private int count = 1;
 boolean flag = false;
 public synchronized void set(String name){
  if(flag){
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.name = name +"--"+count++;
  flag = true;
  System.out.println(Thread.currentThread().getName()+" produce num : "+this.name);
  this.notify();
 }
 public synchronized void out(){
  if(!flag){
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println(Thread.currentThread().getName()+" consume num is : "+this.name);
  flag = false;
  this.notify();
 }
}
class Producer implements Runnable{
 Product res;
 public Producer(Product product) {
  this.res = product;
 }
 @Override
 public void run() {
  while(true){
   res.set("guyue");
  }
 }
}
class Consumer implements Runnable{
 Product res;
 public Consumer(Product product) {
  this.res = product;
 }
 @Override
 public void run() {
  while(true){
   res.out();
  }
 }
}

执行结果如图:

Thread-1 consume num is : guyue--3938
Thread-0 produce num : guyue--3939
Thread-1 consume num is : guyue--3939
Thread-0 produce num : guyue--3940
Thread-1 consume num is : guyue--3940
Thread-0 produce num : guyue--3941
Thread-1 consume num is : guyue--3941

当超过两个以上线程操作的时候,这里需要在set()与out()方法中的if判断改为while,并且notif方法,改为notifyAll(),这样多个线程操作的时候,便可以交替进行,具体代码如下:

public class ThreadProConsume {
 public static void main(String[] args){
  Product product = new Product();
  Thread thread1 = new Thread(new Producer(product));
  Thread thread3 = new Thread(new Producer(product));
  Thread thread2 = new Thread(new Consumer(product));
  Thread thread4 = new Thread(new Consumer(product));
  thread1.start();
  thread3.start();
  thread2.start();
  thread4.start();
 }
}
class Product{
 String name;
 private int count = 1;
 boolean flag = false;
 public synchronized void set(String name){
  while(flag){
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.name = name +"--"+count++;
  flag = true;
  System.out.println(Thread.currentThread().getName()+" produce num : "+this.name);
  this.notifyAll();
 }
 public synchronized void out(){
  while (!flag){
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println(Thread.currentThread().getName()+" consume num is : "+this.name);
  flag = false;
  this.notifyAll();
 }
}

执行结果如下:

Thread-0 produce num : guyue--50325
Thread-2 consume num is : guyue--50325
Thread-1 produce num : guyue--50326
Thread-3 consume num is : guyue--50326
Thread-0 produce num : guyue--50327
Thread-2 consume num is : guyue--50327
Thread-1 produce num : guyue--50328
Thread-3 consume num is : guyue--50328

2、采用Lock-Condition方法实现如下:

class Product{
 String name;
 private int count = 1;
 boolean flag = false;
 Lock lock = new ReentrantLock();
 Condition conditon = lock.newCondition();
 public void set(String name){
  try{
   lock.lock();
   while(flag){
    conditon.await();
   }
   this.name = name +"--"+count++;
   flag = true;
   System.out.println(Thread.currentThread().getName()+" produce num : "+this.name);
   conditon.signalAll();
  }catch (Exception e){
  }finally {
   lock.unlock();
  }
 }
 public void out(){
  try{
   lock.lock();
   while(!flag){
    conditon.await();
   }
   flag = false;
   System.out.println(Thread.currentThread().getName()+" consumer num is : "+this.name);
   conditon.signalAll();
  }catch (Exception e){
  }finally {
   lock.unlock();
  }
 }
}

执行结果如下:

Thread-0 produce num : guyue--20305
Thread-3 consumer num is : guyue--20305
Thread-1 produce num : guyue--20306
Thread-2 consumer num is : guyue--20306
Thread-0 produce num : guyue--20307
Thread-3 consumer num is : guyue--20307
Thread-1 produce num : guyue--20308
Thread-2 consumer num is : guyue--20308

以上就是本文关于Java编程之多线程死锁与线程间通信简单实现代码的全部内容,希望对大家有所帮助。关于Java多线程以及线程间通信的例子,本站还有几篇文章可以参考:

详解java中的互斥锁信号量和多线程等待机制Java多线程编程小实例模拟停车场系统Java网络编程基础篇之单向通信

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

相关文章

  • Java 线程池ExecutorService详解及实例代码

    Java 线程池ExecutorService详解及实例代码

    这篇文章主要介绍了Java 线程池ExecutorService详解及实例代码的相关资料,线程池减少在创建和销毁线程上所花的时间以及系统资源的开销.如果不使用线程池,有可能造成系统创建大量线程而导致消耗系统内存以及”过度切换“
    2016-11-11
  • Java中死锁产生的原因有哪些?

    Java中死锁产生的原因有哪些?

    这篇文章主要介绍了Java中死锁产生的原因有哪些?死锁即Dead Lock指的是两个或两个以上的运算单元,下文关于其产生的原因,需要的小伙伴可以参考一下
    2022-05-05
  • Mybatis Integer类型参数值为0时得到为空的解决方法

    Mybatis Integer类型参数值为0时得到为空的解决方法

    这篇文章主要介绍了Mybatis Integer类型参数值为0时得到为空的解决方法,有需要的朋友们可以学习下。
    2019-08-08
  • Java实现深度搜索DFS算法详解

    Java实现深度搜索DFS算法详解

    深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点。这篇文章主要介绍了基于Java实现深度优先搜索(DFS)算法,需要的朋友可以参考一下
    2021-12-12
  • SpringCloud Edgware.SR3版本中Ribbon的timeout设置方法

    SpringCloud Edgware.SR3版本中Ribbon的timeout设置方法

    今天小编就为大家分享一篇关于SpringCloud Edgware.SR3版本中Ribbon的timeout设置方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 浅谈HTTP使用BASIC认证的原理及实现方法

    浅谈HTTP使用BASIC认证的原理及实现方法

    下面小编就为大家带来一篇浅谈HTTP使用BASIC认证的原理及实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • SpringBoot中动态数据源是实现与用途

    SpringBoot中动态数据源是实现与用途

    这篇文章主要是来和大家讨论一下SpringBoot中动态数据源是实现与用途,文中的示例代码简洁易懂,具有一定的学习价值,感兴趣的可以了解一下
    2023-08-08
  • Java中数据库加密的方式有哪些

    Java中数据库加密的方式有哪些

    这篇文章主要介绍了Java中数据库加密的方式有哪些,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • kafka并发写大消息异常TimeoutException排查记录

    kafka并发写大消息异常TimeoutException排查记录

    这篇文章主要为大家介绍了kafka并发写大消息异常TimeoutException的排查记录及解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • 在Spring Boot中加载初始化数据的实现

    在Spring Boot中加载初始化数据的实现

    这篇文章主要介绍了在Spring Boot中加载初始化数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02

最新评论