学习笔记——JAVA线程<5>线程的死锁

来源:互联网 发布:25岁衣服品牌知乎 编辑:程序博客网 时间:2024/06/05 04:50

死锁:过多的同步容易造成死锁
使用同一份资源谁都不放手就锁住了
模拟死锁

package study;/** * 模拟死锁 * @author http://blog.csdn.net/thewaiting/ * */public class ThreadDome {    public static void main(String[] args) {        Object goods = new Object();        Object money = new Object();        Test t1 = new Test(goods, money);        Test2 t2 = new Test2(goods, money);        Thread proxy = new Thread(t1);        Thread proxy2 = new Thread(t2);        proxy.start();        proxy2.start();    }}class Test implements Runnable {    Object goods = new Object();    Object money = new Object();    public Test(Object goods, Object money) {        super();        this.goods = goods;        this.money = money;    }    @Override    public void run() {        while (true) {            test();        }    }    private void test() {        synchronized (goods) {            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized (money) {            }        }        System.out.println("给钱");    }}class Test2 implements Runnable {    Object goods;    Object money;    public Test2(Object goods, Object money) {        this.goods = goods;        this.money = money;    }    @Override    public void run() {        while (true) {            test();        }    }    private void test() {        synchronized (money) {            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized (goods) {            }        }        System.out.println("给货");    }}

生产者消费者(也成有限缓冲问题)模式解决死锁
先生产 后消费
生产者在缓冲区满时休眠(要么干脆放弃数据)等到下次消费者消耗缓冲区的数据的时候,生产者才能被唤醒开始往缓冲区添加数据。
消费者在缓冲区空时休眠,等到生产者往缓冲区添加数据再唤醒消费者。
通常的方法:信号灯法,管程等
如果解决方法不够完善则容易出现死锁情况
出现死锁时连个线程都会陷入休眠,等待对方唤醒自己

首先模拟一下

package study;//测试public class Text {    public static void main(String[] args) {        //共同的资源        ThreadDome2 t = new ThreadDome2();        //多线程  同时使用资源t        Production p = new Production(t);        Consume c = new Consume(t);        new Thread(p).start();        new Thread(c).start();          }}运行结果生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产 
package study;/** *  * @author http://blog.csdn.net/thewaiting/ * */public class ThreadDome2 {    private String resource;    public void production(String resource) {        this.resource =resource;    }    public void  consume() {        System.out.print(resource+" ");    }}/** * 生产者 * @author http://blog.csdn.net/thewaiting/ * */class Production implements Runnable{    private ThreadDome2 t;//资源    public Production(ThreadDome2 t) {        super();        this.t = t;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            if (0==i%2) {                t.production("生产/被2整除");            }else {                t.production("生产");            }        }    }}/** * 消费者 * @author http://blog.csdn.net/thewaiting/ * */class Consume implements Runnable{    private ThreadDome2 t;    public Consume(ThreadDome2 t) {        super();        this.t = t;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            t.consume();                }    }}

信号灯法

唤醒:
notify() 唤醒在此对象监视器上等待的单个线程
notifyAll() 唤醒在此对象监视器上等待的所有线程
等待:
wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。等待会释放锁sleep()不是释放锁*
以上方法要与同步一起使用,没有同步则无法等待

修改ThreadDome2 代码

package study;/** * 使用生产者消费者模式 * 信号灯法 * @author http://blog.csdn.net/thewaiting/ * */public class ThreadDome2 {    private String resource;    //信号灯    //当flag为true时生产者生产,消费者等待,生产完成后通知消费者    //当flag为false消费者时生产,生产者等待,消费完成后通知生产者    private boolean flag = true;    public synchronized void production(String resource) throws InterruptedException {        if (!flag) {//生产者等待            this.wait();        }        //开始生产        Thread.sleep(500);//模拟生产时间   放大错误的概率        //生产完毕        this.resource =resource;        //通知消费        this.notify();        //生产者停下        this.flag = false;    }    public synchronized void  consume() throws InterruptedException {        if (flag) {//消费者等待            this.wait();        }        //开始消费        Thread.sleep(200);//模拟消费时间   放大错误的概率        System.out.print(resource+" ");        //消费完毕        //通知生产者        this.notify();        //消费停止        this.flag = true;    }}运行结果生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产 生产/被2整除 生产