上一篇中,主要了解了什麼時候死鎖,並且提出死鎖的一個解決方案,多個鎖要按照一定的順序來。

本片主要是利用生產者消費者模式解決執行緒的死鎖。

多執行緒生產者和消費者一個典型的多執行緒程式。一個生產者生產提供消費的東西,但是生產速度和消費速度是不同的。這就需要讓生產者和消費者執行不同的執行緒,通過共享區域或者佇列來協調他們。如下圖所示:
這裡寫圖片描述

程式碼如下:

package deadlock.comsumer_product_solution;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by fang on 2017/12/8.
 * 生產者消費者經典模式.
 */
public class ClassicProducerConsumer {
    public static class Producer implements Runnable{
        private List<Integer> queue;

        private int next = 0;

        public Producer (List<Integer> queue){
            this.queue = queue;//共享資源新增資料.
        }
        public void run() {
            while (true){
                //生產資源.
                synchronized (queue){//鎖住list中的物件.

                    queue.add(next);//生產時鎖住這個陣列
//                    System.out.println("product number" + next + "thread name: " + Thread.currentThread().getName());
                    queue.notifyAll();//喚醒其他執行緒.
                }

                next++;
            }
        }
    }

    public static class Consumer implements Runnable{
        private List<Integer> queue;
        public Consumer(List<Integer> queue){
            this.queue = queue;
        }
        public void run() {
            while (true){
                if(queue.size()>0){
                    Integer number = queue.remove(queue.size() -1);
                    System.out.println("cunsoumer number..."+number + "thread name: " + Thread.currentThread().getName());
                }else {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String args[]) throws Exception{
        List<Integer> queue = new ArrayList<Integer>();
        Thread producter1 = new Thread(new Producer(queue),"product1 thread");
        Thread producter2 = new Thread(new Producer(queue),"product2 therad");
        Thread consumer1 = new Thread(new Consumer(queue),"consumer1 therad");
        Thread consumer2 = new Thread(new Consumer(queue),"consumer2 therad");

        producter1.start();
        producter2.start();
        consumer1.start();
        consumer2.start();
    }
}

自從java1.5之後有很多容易的方式去實現生產者和消費者方案,最好的方式就是使用a blocking queue。

package deadlock.comsumer_product_solution;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.SynchronousQueue;

/**
 * Created by fang on 2017/12/8.
 * using block queue .
 */
public class producerConsumerWithBlockingQueue {

    public static class Producer implements Runnable{
        private BlockingQueue<Integer>queue;
        private int next = 0;

        public Producer(BlockingQueue<Integer> queue){
            this.queue = queue;
        }
        public void run() {
            while (true){
                try {
                    queue.put(next);
                    System.out.println(next + "product");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                next++;
            }
        }
    }

    public static class Consumer implements Runnable{
        private BlockingQueue<Integer> queue;
        private Consumer(BlockingQueue<Integer> queue){
            this.queue = queue;
        }
        public void run() {
            while (true){
                synchronized (queue){
                    Integer next ;
                    try {
                        next = queue.take();
                        System.out.println(next+"consumer");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }
    }

    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new LinkedBlockingDeque<Integer>(1);

        Thread producer1 = new Thread(new Producer(queue));
        Thread producer2 = new Thread(new Producer(queue));
        Thread consumer1 = new Thread(new Consumer(queue));
        Thread consumer2 = new Thread(new Consumer(queue));
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();    }
}

如果有一個生產者和一個消費者,我們可以使用count down latch,程式碼如下:

package deadlock.comsumer_product_solution;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Created by fang on 2017/12/8.
 * countdownlatch
 */
public class ProducerConsumerWithCountDownLatch {
    public static class Producer implements Runnable {
        private List<Integer> queue;
        private CountDownLatch latch;
        private int next = 0;

        public Producer(List<Integer> queue,CountDownLatch latch) {
            this.queue = queue;
            this.latch=latch;
        }

        public void run() {
            while (true) {
                synchronized (queue) {
                    queue.add(next);
                    System.out.println(next + "producer");
                    latch.countDown();
                }
                next++;
            }
        }
    }

    public static class Consumer implements Runnable {
        private List<Integer> queue;
        private CountDownLatch latch;

        public Consumer(List<Integer> queue,CountDownLatch latch) {
            this.queue = queue;
            this.latch=latch;
        }

        public void run() {
            while (true) {
                Integer number=null;
                synchronized (queue) {
                    if (queue.size() > 0) {
                        number = queue.remove(queue.size()-1);
                        System.out.println(number+"consumer");
                    }
                }
                if(number==null) {
                    try {
                        latch.await();
                    } catch (InterruptedException e) {
                    }
                }
            }
        }
    }

    public static void main(String args[]) throws Exception {
        List<Integer> queue = new ArrayList<Integer>();
        CountDownLatch latch=new CountDownLatch(1);
        Thread producer1 = new Thread(new Producer(queue,latch));
        Thread consumer1 = new Thread(new Consumer(queue,latch));
        producer1.start();
        consumer1.start();
    }
}

如果一個生產者和一個消費者,我們還可以使用Exchanger,程式碼如下:

 package deadlock.comsumer_product_solution;

 import java.util.concurrent.Exchanger;

 /**
  * Created by fang on 2017/12/8.
  * 使用exchanger.
  */
 public class ProducerConsumerWithExchanger {
     public static class Producer implements Runnable {
         private Exchanger<Integer> exchanger;
         private int next = 0;

         public Producer(Exchanger<Integer> exchanger) {
             this.exchanger=exchanger;
         }

         public void run() {
             while (true) {
                 try {
                     exchanger.exchange(next);
                     System.out.println(next  +"producer");
                 } catch (InterruptedException e) {
                 }
                 next++;
             }
         }
     }

     public static class Consumer implements Runnable {
         private Exchanger<Integer> exchanger;
         public Consumer(Exchanger<Integer> exchanger) {
             this.exchanger=exchanger;
         }

         public void run() {
             while (true) {
                 try {
                     System.out.println(exchanger.exchange(0) + "consumer");
                 } catch (InterruptedException e) {
                 }
             }
         }
     }

     public static void main(String args[]) throws Exception {
         Exchanger<Integer> exchanger=new Exchanger<Integer>();
         Thread producer1 = new Thread(new Producer(exchanger));
         Thread consumer1 = new Thread(new Consumer(exchanger));
         producer1.start();
         consumer1.start();
     }
 }

以上幾種方式就是實現生產者和消費者解決方案,同時也解決了死鎖問題。