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
时间: 2024-10-09 22:06:54

Java多线程之死锁与线程间通信简单案例的相关文章

黑马程序员——JAVA基础之Day24 多线程 ,死锁,线程间通信 ,线程组,线程池,定时器。

------- android培训.java培训.期待与您交流! ---------- Lock()实现提供了比使用synchronized方法和语句可获得更广泛的锁定操作. private Lock lock =new ReentrantLock(); 被锁的代码要用   lock.lock()                lock.unlock()    包括.其中用try   ...finally包围 同步:效率低,如果出现同步嵌套,会出现死锁.  但是安全. 死锁问题:两个或者两个以上

Java多线程-管道流实现线程间通信

管道流 在Java语言中提供了各种各样的输入/输出流 Stream ,使我们能够很方便地对数据进行操作,其中管道流是一种特殊的流,用于在不同线程间直接传送数据.一个线程发送数据到输出管道流,另一个线程从输入管道流中读取数据. 通过使用管道,实现不同线程间的通信,而无须借助于类似临时文件之类的东西. 字节流 PipedInputStream 和 PipedOutputStream 字符流 PipedReader 和 PipedWriter 示例: public class PipeStreamTe

多线程学习笔记四--------------线程间通信问题

线程间通信问题: 多个线程在处理同一资源,但是任务却不同: java中将资源共享的方法(思路): 1.方法或者变量静态化---->静态化后,在类加载的时候,会将其加载到内存的方法区进行共享 2.单例设计模式---->保证只对一个实例进行操作. 3.将资源作为操作该资源的类的构造函数的参数,这样可以保证此类的多个对象在使用该资源的时候使用该资源的同一个实例. 现在我们要用第三种方法来进行线程间的通信. 情景:两个线程 ,一个负责输入,一个负责输出:共同处理一个资源. public class T

java多线程详解(6)-线程间的通信wait及notify方法

Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New):线程对象已经产生,但尚未被启动,所以无法执行.如通过new产生了一个线程对象后没对它调用start()函数之前.(2). 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它. 当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它

Java 多线程(七) 线程间的通信——wait及notify方法

线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html 因为wait和notify方法定义在Object类中,因此会被所有的类所继承. 这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为. wait()方法 wait()方法使得当前线程必须要等

多线程编程学习三(线程间通信)

一.概要 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一.可以说,使线程进行通信后,系统之间的交互性会更强大,在大大提高cpu利用率的同时还会使程序员对各线程任务在处理过程中进行有效的把控和监督. 二.等待/通知机制 1."wait/notify"机制:等待/通知机制,wait使线程暂停运行,而notify 使暂停的线程继续运行.用一个厨师和服务员的交互来说明: (1) 服务员取到菜的时间取决于厨师,所以服务员就有“

生产者消费者中多线程安全问题(即线程间通信的安全问题)

一个生产线程,一个消费线程,程序不存在安全问题 两个生产线程,两个消费线程,出现了生产两次,消费一次或者生产一次,消费两次的情况. 出现问题的原因是:线程被唤醒之后没有回去判断标记,直接继续执行后边的代码. 解决方式:让线程被唤醒之后不是直接执行后边的代码,而是回去判断标志,这个问题可以通过把if改成while实现.          但这样做会出现死锁的状况,原因是唤醒了本方线程,导致所有线程全部等待.          notify()唤醒的是任意一个线程,不能保证唤醒的是对方线程,这个问题

Java 多线程(八) 线程状态图

结合多线程的学习过程,介绍线程的状态图,随着学习的深入,这幅图不断加入新的内容. 一.线程基本状态图 这幅图是在Java 多线程(三) 线程的生命周期及优先级出现过的: 图中是线程运行的基本状态:线程调用start()方法开始后,就进入到可运行状态,随着CPU的资源调度在运行和可运行之间切换:遇到阻塞则进入阻塞状态. 二.加入同步的线程状态图 多线程的同步机制,及synchronized关键字的使用学习: Java 多线程(五) 多线程的同步 Java 多线程(六) synchronized关键

Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会引起此共享资源的不一致性.因此,为避免线程安全问题,应该避免多线程环境下对此共享资源的并发访问. 线程安全问题多是由全局变量和静态变量引起的,当多个线程对共享数据只执行读操作,不执行写操作时,一般是线程安全的:当多个线程都执行写操作时,需要考虑线程同步来解决线程安全问题. 二.线程同步(synchr