死锁&线程通信

本文介绍了Java中死锁的概念和示例,探讨了线程间通信的重要性,特别是wait和notify方法的使用,以及生产者消费者问题的解决方案。通过实例展示了如何避免死锁并管理多线程间的协作。
摘要由CSDN通过智能技术生成

1.死锁

>概述

不同的线程分别占用着对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

一旦出现死锁,整个程序既不会放生异常,也不会给出任何提示,只是所有线程都处于阻塞状态,无法继续

>死锁的代码实现

public class _01_Deadlock_01  {
    public static void main(String[] args) {

        Thread t1 = new A();
        Thread t2 = new A();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

class A extends Thread {
    static Object o1 = new Object();
    static Object o2 = new Object();

    @Override
    public void run() {

            if ("线程1".equals(getName())) {
                synchronized (o1) {
                    System.out.println("o1被锁定");
                    synchronized (o2) {
                        System.out.println("o2被锁定");
                    }
                }
            }
            else if("线程2".equals(getName())){
                synchronized (o2) {
                    System.out.println("o2被锁定");
                    synchronized (o1) {
                        System.out.println("o1被锁定");
                    }
                }
            }
    }
}

2.线程通信

>概述

1)为什么要处理线程通信?

当我们需要多个线程来共同完成一项任务,并且我们希望它们有规律的执行,那么多线程之间需要一些通信机制,来协调它们的工作,以此实现多线程共同操作一份数据

2)调用wait和notify方法需要注意的细节

-- wait方法与notify方法必须要有同一个锁对象调用,对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程

-- wait方法与notify是属于Object类的方法

-- wait方法和notify方法必须要在同步代码块或同步方法中使用

>使用案例

public class _04_Wait_01 {
    public static void main(String[] args) throws InterruptedException {
        Num num = new Num();
        Thread t1 = new Thread(new PrintOdd(num));
        Thread t2 = new Thread(new PrintEven(num));
        t1.setName("打印奇数");
        t2.setName("打印偶数");
        t1.start();
        Thread.sleep(100);
        t2.start();
    }
}
//打印奇数的类
class PrintOdd implements Runnable{
    Num num;
    public PrintOdd(Num num){
        this.num = num;
    }
    @Override
    public void run() {
        while (true) {
            num.printnum();
        }
    }
}
//打印偶数的类
class PrintEven implements Runnable{
    Num num;
    public PrintEven(Num num){
        this.num = num;
    }
    @Override
    public void run() {
        while (true) {
            num.printnum();
        }
    }
}

class Num{
    private int count = 1;
    public synchronized void printnum(){
        System.out.println(Thread.currentThread().getName() + ":" + count);
        //每次打印完自增1
        count++;
            notify();
        try {
            Thread.sleep(100);
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

>生产者与消费者问题

生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程,与此同时,消费者也在缓冲区中消耗这些数据,此问题的关键是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据

详细介绍:https://www.cnblogs.com/ldddd/p/15770457.html

代码案例

public class Exer3 {
    public static void main(String[] args) {
        Cook c = new Cook();
        Foodie f = new Foodie();
        c.setName("厨师");
        f.setName("吃货");
        c.start();
        f.start();
    }
}
//消费者
class Foodie extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized(Desk.lock){
                //如果桌子上没有食物 就终止线程
                if(Desk.count == 0){
                    break;
                }else{
                    //判断桌子上是否有食物
                    if(Desk.FoodFlag == 0) {  //如果没食物 就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else{  //如果有食物 就开吃
                        Desk.count--;
                        System.out.println("正在吃,还能吃" + Desk.count + "碗");
                        //修改桌子的状态
                        Desk.FoodFlag = 0;
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}
//生产者
class Cook extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized(Desk.lock){
                //如果桌子上的食物满了 就终止线程
                if(Desk.count == 0){
                    break;
                }else{
                    //判断桌子上是否有食物
                    if(Desk.FoodFlag == 1){
                        //如果有 就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else{  //如果没有食物 就做
                        System.out.println("做了一碗饭");
                        //修改桌子的状态
                        Desk.FoodFlag = 1;
                        //等待消费者吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}
//用于控制生产者和消费者的执行
class Desk{
    //桌子上是否有食物 0没有 1有
    public static int FoodFlag = 0;
    //总个数
    public static int count = 10;
    //锁对象
    public static Object lock = new Object();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值