我试图了解同步块。在这里,我实现了一个生产者线程和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)
答案 0 :(得分:1)
您还必须锁定添加。您的代码允许生产者更新队列,而消费者可能想要删除条目!
当两个线程并行修改同一队列时,所有投注都会关闭!
单一锁定使用只会阻止多个消费者相互踩踏!
因此:为添加值的部分添加相同类型的锁定。
除此之外,EJP是正确的 - 一个真正的解决方案将使用低级信令方法,如wait()和notify()。但是,当然,使用这些会导致一种非常不同的行为。
并给出你的评论:请记住,这些是两个不同的东西:A)消费者/生产者彼此发送信号B)消费者/生产同步的同步。
我知道你不想要&#34; A)&#34; - 但你需要&#34; B)&#34 ;;否则你的队列会被破坏,并会出现意外。
答案 1 :(得分:0)
您应该在此处调用 wait()方法 wait()让你的线程等到其他一些线程调用通知唤醒他 sleep()根本不执行指定时间段的下一个语句 如果您看到程序片段,则使用同步块,该块使用对象检查监视器的可用性。但是您没有使用任何对象监视器方法 wait / notify / notifyAll ,并且您尝试获取并释放锁定而不调用这些方法。由于,消费者和生产者使用的列表对象,您应该使用此列表对象监视器来同步所有线程。如果一个线程获得了它的监视器,那么其他线程将无法访问它。因为每个对象只有一个监视器。这种方法将解决所有工作线程之间的同步问题。
答案 2 :(得分:0)
问题是你的Store
类实现。在添加和删除元素时,您需要在那里实现wait()
和notify
机制,而不是休眠。
您在所有消费者和制作人之间共享单个Store
实例是正确的,但您的商店需要表现得像BlockingQueue
因此,要么使用JDK中的BlockingQueue
的现有实现,要么修改Store
类以实现类似的机制。
implement-your-own blocking queue in java
希望它有所帮助!!