Java 高并发编程 -死锁-生产者消费者模式

线程同步:就是在执行代码的时候,同一个资源,被多个线程访问,此时协调这多个线程得访问就是线程同步。

解决比较简单的一种方法是,实用synchronized 同步锁,让下一个线程等待上一个线程执行结束。然后执行,在上synchronized锁得时候,需要注意,这把锁的粒度。

在上synchronized锁得时候经常会碰见的一个问题是,『死锁』

前提:俩个或以上的线程
线程A,整个操作过程中锁住了a(先)对象和b(后)对象。
线程B,整个操作过程中锁住了b(先)对象和a(后)对象。

线程A 将a对象执行完了,执行到b对象的时候,发现b对象已经被线程B锁定,那么线程A就在等待中,a的锁是不会释放。
线程B执行完b对象的操作的时候,发现a对象已经被A线程给锁定,于是也进入等待,此时b得锁也是不会释放。

于是线程A和线程B都等待对方释放锁,于是两个线程就都执行不下去了
public class Account implements Runnable{
    public int flag = 1;
    static Object o1 = new Object();
    static Object o2 = new Object();
    @Override
    public void run() {
        System.out.println("flag= " + flag);
        if (flag == 1){
            synchronized (o1){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o2){
                    System.out.println("1");
                }
            }
        }
        if (flag==0){
            synchronized (o2){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (o1){
                    System.out.println("0");
                }
            }
        }
    }
    public static void main(String[] args){
        Account t1 = new Account();
        Account t2 = new Account();

        t1.flag=1;
        t2.flag=0;

        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();
        thread2.start();
    }
}

程序会一直在这里执行,

解决死锁得方法:

  • 最好只锁住一个,不要锁住多个,也就是将锁得粒度加粗一些
  • 锁定当前整个对象就可以了,为什么要在这个对象下面锁定两个小对象呢?
  • 锁的粒度加粗些,当然还有很多其它的办法

生产者-消费者模式

package Basic;

public class ProducerConsumer{

    public static void main(String[] args){
        SyncStack syncStack = new SyncStack();
        Producer producer = new Producer(syncStack);
        Consumer consumer = new Consumer(syncStack);

        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

/*
    馒头类
    id: 每一个馒头得id
 */
class WoTou{
    int id;

    public WoTou(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "WoTou{" + "id=" + id + '}';
    }
}

class SyncStack{
    int index = 0;
    WoTou[] arrWT = new WoTou[6];
    /*
        装馒头
     */
    public synchronized void push(WoTou woTou){
        while (index == arrWT.length){
            /*
                这里主要的是 wait 这个等待方法,执行这个方法的前提是 synchronized 将这个对象锁住
                锁住之后才能去 wait 等待,等待过程中会释放锁

                当等待之后,这个对象的锁就不在归我管理了,只有当我醒来的时候,采取找这把锁

                当一个线程来给我塞馒头得时候,如果这个时候,馒头已经塞满了,不能再往里面塞了
                那么就要去阻塞住,

                等待消费者将馒头买完,才能继续生产(塞馒头)
             */

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        /*
            wait 和 notify 得方法是一致的,
            notify 方法叫醒一个正在wait在我这个对象上的方法,让他继续执行
            notifyAll 方法叫醒所有正在wait在我这个对象上的方法,让他继续执行
         */
        this.notify();
        arrWT[index] = woTou;
        index ++;
    }
    /*
        吃馒头
     */
    public synchronized WoTou pop(){
        while (index==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.notify();
        index --;
        return arrWT[index];
    }
}

/*
    生产者一次生产 20 个馒头
 */
class Producer implements Runnable{
    SyncStack ss = null;

    public Producer(SyncStack ss) {
        this.ss = ss;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou woTou = new WoTou(i);
            ss.push(woTou);
            System.out.println("生产了:" + woTou);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/*
    消费者一次吃 20 个馒头
 */
class Consumer implements Runnable{
    SyncStack ss = null;

    public Consumer(SyncStack ss) {
        this.ss = ss;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou pop = ss.pop();
            System.out.println("消费了:" + pop);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

原文链接

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值