您当前的位置: 首页 > 

梁云亮

暂无认证

  • 2浏览

    0关注

    1211博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

多线程 之 线程死锁

梁云亮 发布时间:2020-02-23 13:37:20 ,浏览量:2

相关博客:多线程 之 线程同步

通过生产者消费者模拟线程死锁
  • 产品池
public class ProductPool {
    private int threshold = 1; //仓库中只能存一个产品
    private LinkedList pool = new LinkedList();//放产品

    //同一时刻只能有一个人生产
    public synchronized void add(Integer item) {
        String name = Thread.currentThread().getName();
        while (pool.size() >= threshold) {
            try {
                System.out.println(name+".wait()");
                this.wait(); // 在等待之前不发送通知  //----------- ②
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.add(item);
        System.out.println(name +"生产后总数量:"+pool.size());
        System.out.println(name+"调用notify()发送了通知");//在notify之前打印,说明已经出队列了
        notify();//增加完商品之后,通知别的线程可以生产or消费了  //------- ①
    }

    // 同一时刻只能有一个人消费
    public synchronized void remove() {
        String name = Thread.currentThread().getName();
        while (pool.isEmpty()) {
            try {
                System.out.println(name+".wait()");
                this.wait();//如果仓库中没有产品,线程就等着  //----------- ②
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.removeFirst();
        System.out.println(name+"消费后总数量:"+pool.size());

        System.out.println(name+"调用notify()发送了通知");//在notify之前打印,说明已经出队列了

        notify();//消费完商品之后,通知别的线程可以生产or消费了  //------- ①
    }
}
  • 生产者
public class Producer extends Thread {
    private static int index = 0;

    private ProductPool pool;

    public Producer(  ProductPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的生产
            pool.add(index++);
        }
    }
}
  • 消费者
public class Consumer extends Thread {
    private ProductPool pool;

    public Consumer(  ProductPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        while (true) {//在产品池中不断的消费
            pool.remove();
        }
    }
}
  • 测试代码
public class DemoTest {
    public static void main(String[] args) {//一个生产者,两个消费者
        ProductPool pool = new ProductPool();
        Producer p1 = new Producer(pool);
        p1.setName("p1");
        Consumer c1 = new Consumer(pool);
        c1.setName("c1");
        Consumer c2 = new Consumer(pool);
        c2.setName("c2");
        p1.start();
        c1.start();
        c2.start();
    }
}

某次运行程序,结果如下: 在这里插入图片描述

解决方案:notifyAll()
  • notify:通知一个线程
  • notifyAll:通知线程等待队列中的所有线程 不管是notify()还是notifyAll()它们都只是发出通知,不会释放锁控制权。

解决方案:修改产品池 编号①处的代码为notifyAll();修改之后产品池代码如下:

public class ProductPool {
    private int threshold = 1; //仓库中只能存一个产品
    private LinkedList pool = new LinkedList();//放产品

    //同一时刻只能有一个人生产
    public synchronized void add(Integer item) {
        String name = Thread.currentThread().getName();
        while (pool.size() >= threshold) {
            try {
                System.out.println(name + ".wait()");
                this.wait(); // 在等待之前不发送通知
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.add(item);
        System.out.println(name + "生产后总数量:" + pool.size());
        System.out.println(name + "调用notify()发送了通知");//在notify之前打印,说明已经出队列了
        notifyAll();//增加完商品之后,通知别的线程可以生产or消费了
    }

    // 同一时刻只能有一个人消费
    public synchronized void remove() {
        String name = Thread.currentThread().getName();
        while (pool.isEmpty()) {
            try {
                System.out.println(name + ".wait()");
                this.wait();//如果仓库中没有产品,线程就等着
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.removeFirst();
        System.out.println(name + "消费后总数量:" + pool.size());

        System.out.println(name + "调用notify()发送了通知");//在notify之前打印,说明已经出队列了

        notifyAll();//消费完商品之后,通知别的线程可以生产or消费了
    }
}
解决方案:限时等待: wait(1000)

修改编号 ②处的代码,让等待队列中的线程不再是一直等,只需要等待具体的时间就行了。 修改之后,产品池代码如下所示:

  public class ProductPool {
    private int threshold = 1; //仓库中只能存一个产品
    private LinkedList pool = new LinkedList();//放产品

    //同一时刻只能有一个人生产
    public synchronized void add(Integer item) {
        String name = Thread.currentThread().getName();
        while (pool.size() >= threshold) {
            try {
                System.out.println(name+".wait()");
                this.wait(300); // 在等待之前不发送通知
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.add(item);
        System.out.println(name +"生产后总数量:"+pool.size());
        System.out.println(name+"调用notify()发送了通知");//在notify之前打印,说明已经出队列了
        notify();//增加完商品之后,通知别的线程可以生产or消费了
    }

    // 同一时刻只能有一个人消费
    public synchronized void remove() {
        String name = Thread.currentThread().getName();
        while (pool.isEmpty()) {
            try {
                System.out.println(name+".wait()");
                this.wait(300);//如果仓库中没有产品,线程就等着
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Integer res = pool.removeFirst();
        System.out.println(name+"消费后总数量:"+pool.size());

        System.out.println(name+"调用notify()发送了通知");//在notify之前打印,说明已经出队列了

        notify();//消费完商品之后,通知别的线程可以生产or消费了
    }
}
练习题:100只蜜蜂,每只蜜蜂每次生产数量蜂蜜量为1。2只熊消费蜂蜜,每只熊都会在蜜罐中的蜂蜜满20时会将蜂蜜吃掉。

知识点:wait()、notify()2个方法 wait()方法让线程进入线程等待队列当中,它的2个重要特点是:1、失去cpu抢占权。2、失去线程对象的监控权,此时没有锁可以锁住线程。与线程的sleep()方法的区别:sleep()方法仅仅只是失去cpu的抢占权,并不会失去对象的监控权。 notify()方法,唤醒在线程等待队列中的线程,注意线程是不能自我唤醒的,线程在运行当中,就没有在线程等待队列当中就没有所谓的唤醒,只有进入线程等待队列,才能被唤醒,也只能是被其它排除自己的线程所唤醒。

练习题:40个员工,一个篮子装有100个馒头,员工吃馒头并发执行,每个工人最少吃1个最多吃3个馒头,问在这种情况下怎么分配。
关注
打赏
1665409997
查看更多评论
立即登录/注册

微信扫码登录

0.0447s