2016-10-13 3 views
0

Чтобы понять, как работает Multi Threading, я использую Queue и ReentrantLock для моделирования проблемы производителя и потребителя. Мой поток производителя добавляет данные в очередь, но потребитель не удаляет. Я не уверен, правильно ли я это сделал. Я понимаю, что это уже было задано, но они не помогают.Потребитель-производитель с использованием ReentrantLock и Queue

пакет параллелизма;

import java.util.Queue; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.ReentrantLock; 


class Producer implements Runnable{ 
    Queue<Integer> list; 
    Condition con; 
    ReentrantLock lock; 
    int size; 


    Producer(Queue q1, Condition con, ReentrantLock l1,int size) 
    { 
     this.list=q1; 
     this.con=con; 
     this.lock=l1; 
     this.size=size; 
    } 

    public void run() 
    { 
     for(int i =0;i<20;i++) 
     { 
      if(lock.tryLock()) 
      { 
       while(list.size()==size) 
       { 
        try 
        { 
         con.await(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       list.add(i); 
       System.out.println("Producer "+ Thread.currentThread() +"added "+i+" to the List"); 
       con.signalAll(); 
       lock.unlock(); 

      } 
     } 
    } 
} 


class Consumer implements Runnable{ 
    Queue<Integer> list; 
    Condition con; 
    ReentrantLock lock; 
    int size; 

    Consumer(Queue q1, Condition con, ReentrantLock l1,int size) 
    { 
     this.list=q1; 
     this.con=con; 
     this.lock=l1; 
     this.size=size; 
    } 

    public void run() 
    { 

     for(int innerLoop =0;innerLoop<20;innerLoop++){ 
      if(lock.tryLock()){ 
       while(list.size()<1){ 
        try { 
         con.await(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       int i = (int) list.remove(); 
       System.out.println("Consumer "+ Thread.currentThread() +"removed "+i+" from the List"); 
       con.signalAll(); 
       lock.unlock(); 
      } 
     } 
    } 
} 

class SharedResource { 

    Queue list ; 

    Condition con; 
    ReentrantLock lock; 
    int size; 

    SharedResource() 
    { 
     size =20; 
     this.list=new LinkedList<Integer>(); 
     lock = new ReentrantLock(); 
     this.con = lock.newCondition(); 


    } 

    public Queue getList() { 
     return list; 
    } 

    public void setList(Queue list) { 
     this.list = list; 
    } 

    public Condition getCon() { 
     return con; 
    } 

    public void setCon(Condition con) { 
     this.con = con; 
    } 

    public ReentrantLock getLock() { 
     return lock; 
    } 

    public void setLock(ReentrantLock lock) { 
     this.lock = lock; 
    } 

    public int getSize() { 
     return size; 
    } 

    public void setSize(int size) { 
     this.size = size; 
    } 

} 

public class MYPRODUCERCONSUMER { 




    public static void main(String[] args) { 

     SharedResource producerCObj = new SharedResource(); 
     Producer producer= new Producer(producerCObj.getList(), producerCObj.getCon(), producerCObj.getLock(), producerCObj.getSize()); 
     Thread producerThread= new Thread(producer); 
     producerThread.start(); 

     Consumer consumer= new Consumer(producerCObj.getList(), producerCObj.getCon(), producerCObj.getLock(), producerCObj.getSize()); 
     Thread consumerThread= new Thread(consumer); 
     consumerThread.start(); 
    } 

} 
+0

Начните с осознания, что здесь нет смысла делать блокировку. ArrayBlockingQueue является потокобезопасным и блокирует потоки, когда им нечего делать. Вы можете удалить все вещи с помощью замков и условий. –

+1

@Nathan Hughes Я хочу понять, как работать с блокировкой и условиями, поэтому я изменил ArrayBlockingQueue на LinkedList. – crazyStart

ответ

1

В вашем потребителя вы пытаетесь приобрести замок:

if(lock.tryLock()) 

Но tryLock получает блокировку, только если он не другим потоком во время вызова. Просто потому, что вы сначала начинаете продюсера, весьма вероятно, что он уже приобретен Продюсером. Вы пытаетесь сделать unlock, но следующая инструкция: tryLock (в цикле), поэтому нет никакого урона для другой темы. Другими словами, Потребительский поток почти не имеет шансов получить блокировку, потому что продюсерская нить его повторно приобретает. И только потому, что у вас конечный цикл (всего 20), ваш потребитель просто заканчивается.

Если добавить

class Producer implements Runnable{ 
Queue<Integer> list; 
Condition con; 
ReentrantLock lock; 
int size; 


    Producer(Queue q1, Condition con, ReentrantLock l1,int size) 
    { 
     this.list=q1; 
     this.con=con; 
     this.lock=l1; 
     this.size=size; 
    } 

    public void run() 
    { 
     for(int i =0;i<20;i++) 
     { 
      if(lock.tryLock()) 
      { 
       while(list.size()==size) 
       { 
        try 
        { 
         con.await(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       list.add(i); 
       System.out.println("Producer "+ Thread.currentThread() +"added "+i+" to the List"); 
       con.signalAll(); 
       lock.unlock(); 

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

после

lock.unlock(); 

в цикле Producer вы дать шанс потребителей нить приобрести замок, и вы получите результат, как и ожидалось.

+0

Я попытался добавить Thread.sleep, но все же мой поток производителя только начинает выполняться. – crazyStart

+0

Я отредактировал ответ с полным кодом Продюсера. Также попробуйте увеличить время сна. Однако он работает на моем Mac с 10. –

Смежные вопросы