2017-04-14 5 views
1

동기화 된 블록을 이해하려고합니다. 여기서는 하나의 제작자 스레드와 2 개의 소비자 스레드를 구현했습니다.자바 멀티 스레딩 : 느린 프로듀서 및 고속 사용자

LinkedList가 비어있어 스레드에서 예외가 계속 발생합니다.

package com.Main; 

import com.qed.Consumer; 
import com.qed.Producer; 
import com.qed.Store; 

public class Main { 

public static void main(String[] args) throws InterruptedException { 
    Store st = new Store(); 

    Thread populate = new Thread(new Producer(st)); 
    Thread con1 = new Thread(new Consumer(st)); 
    Thread con2 = new Thread(new Consumer(st)); 
    con1.setName("A"); 
    con2.setName("B"); 
    populate.start(); 
    con1.start(); 
    con2.start(); 

    populate.join(); 
    con1.join(); 
    con2.join(); 
    if(populate.isAlive()){ 
     con1.interrupt(); 
     con2.interrupt(); 
    } 
    } 
} 

package com.qed; 

import java.util.LinkedList; 

public class Store { 

private LinkedList<Integer> qu = new LinkedList<Integer>(); 
private final Object lock = new Object(); 

public void add(int data){ 
    try{ 
     while(qu.size() ==10){ 
      Thread.sleep(1); 
      } 
     qu.add(data); 
    }catch(InterruptedException ie){ 
     ie.printStackTrace(); 
    } 
} 

public int remove(){ 
    int data=0; 
    try{ 
     synchronized(lock){ 
      while(qu.size() == 0){ 
       Thread.sleep(1); 
       } 
      data = qu.removeFirst(); 
     } 
    }catch(InterruptedException ie){ 
     ie.printStackTrace(); 
    } 
    return data; 
    } 
} 

package com.qed; 

public class Consumer implements Runnable{ 

private Store st; 
public Consumer(Store st){ 
    this.st=st; 
} 


public void run(){ 
    while(true){ 
     System.out.println(Thread.currentThread().getName() + ". " +st.remove()); 
    } 
    } 
} 

package com.qed; 

public class Producer implements Runnable{ 

private Store st; 
private final int runs = 5000; 
public Producer(Store st){ 
    this.st = st; 
} 

public void run(){ 
    int data = 0; 
    int curRun =0; 
    while(++curRun < runs){ 
     st.add(data+=200); 
     } 
    System.out.println("DONE."); 
    } 
} 

스택 추적 :

Exception in thread "B" Exception in thread "A" 
java.util.NoSuchElementException  
    at java.util.LinkedList.removeFirst(Unknown Source)  
    at com.qed.Store.remove(Store.java:46)  
    at com.qed.Consumer.run(Consumer.java:20)  
    at java.lang.Thread.run(Unknown Source)  
java.util.NoSuchElementException  
    at java.util.LinkedList.removeFirst(Unknown Source)  
    at com.qed.Store.remove(Store.java:46)  
    at com.qed.Consumer.run(Consumer.java:20)  
    at java.lang.Thread.run(Unknown Source)  
+2

'add()'에서 동기화하지 않으면 정의되지 않은 동작입니다. – 1000ml

답변

1

당신은뿐만 아니라 추가에 고정해야합니다. 사용자가 항목을 제거하려고 할 때 생성자가 코드를 사용하여 큐를 업데이트 할 수 있습니다.

두 스레드가 동일한 큐를 병렬로 수정하면 모든 내기가 꺼집니다!

단일 잠금을 사용하면 여러 소비자가 서로 밟을 수 없습니다.

따라서 : 값을 추가하는 섹션에 대해 동일한 종류의 잠금을 추가하십시오.

그 외에도 EJP는 정확합니다. 실제 솔루션은 wait() 및 notify()와 같은 저수준 신호 방식을 사용합니다. 물론 이들을 사용하면 매우 다른 행동으로 이어질 것입니다.

그리고 의견을 말하면 다음 두 가지 사항을 명심하십시오. A) 소비자/생산자가 서로에게 신호를 보내고 B) 소비자/동일한 모양으로 동기화를 생성합니다.

"A"를 원하지 않는다고 이해하지만 에는 "B)"가 필요합니다. 그렇지 않으면 대기열이 손상되고 놀라움이 발생합니다.

+0

맞지만, 그는 잠자는 대신'wait()'할 필요가 있고, 추가하거나 제거 할 때'notify()'해야합니다. – EJP

+0

예 아니요. 나는 그가 여기에서 실험하고 있다고 생각한다. 신호를 사용하는 것이 자연스럽게 보일 것입니다. 그러나 그에 따라 대답을 업데이트했습니다. 감사. – GhostCat

+0

@GhostCat 맞습니다. 나는 여기서 실험하고있다. 나는 하나의 생성자 스레드가 큐가 가득 찰 때까지 추가를 계속할 수있는 큐를 구현하려고하는데 소비자는 큐를 한 번에 하나씩 비울 수있다. 나는 생산자와 소비자가 서로 존중하지 않는 메커니즘을 구현하려고한다. 나는 read 메소드가 소비자가 사용하는 것과 같은 락에서 동기화를 사용해야하기 때문에 wait와 notify를 사용하고 싶지 않다. 이것은 소비자가 remove 메소드에 액세스하는 동안 생산자가 잠길 것이라는 내 목적에 어긋납니다. – Manik

0

여기서 () 방법을 호출해야합니다.
wait()은 다른 스레드 호출이 그를 깨우라고 알릴 때까지 스레드를 대기시킵니다.
sleep() 단순히 지정된 기간 동안 다음 명령문을 실행하지 마십시오.
그리고 프로그램 스 니펫이 보이면 객체를 사용하여 모니터 가용성을 확인하는 동기화 블록을 사용하고 있습니다. 그러나 객체 모니터 메소드 wait/notify/notifyAll을 사용하지 않고 있으며 이러한 메소드를 호출하지 않고 잠금을 획득하고 해제하려고합니다. 소비자와 생산자가 모두 사용하는 목록 객체이므로이 목록 객체 모니터를 사용하여 모든 스레드를 동기화해야합니다. 1 개의 thread가 그 모니터를 취득하면 (자), 다른 thread가 그 thread에 액세스 할 수 없습니다. 왜냐하면 모든 객체에는 하나의 모니터 만 있기 때문입니다. 이 방법은 모든 작업 스레드 간의 동기화 문제를 해결합니다.

0

문제는 Store 클래스 구현입니다. 잠자는 대신 요소를 추가 및 제거하는 동안 wait()notify 메커니즘을 구현해야합니다.

당신은 모든 소비자와 생산자 사이에 하나의 Store 인스턴스를 공유하는 정확하지만, 상점은 JDK에서 BlockingQueue 기존의 구현을 사용 또는 유사한 구현하기 위해 Store 클래스를 수정 그래서 중 하나 BlockingQueue

처럼 행동 할 필요가 기구.

implement-your-own blocking queue in java

는 희망이 도움이!