一个线程如何在不发生"current Thread is not owner"故障的情况下与另一个线程通信?



所以我正在尝试在Java中重建消费者/生产者模式。我创建了 20 个 ListInserter(生产者)和 20 个 ListNibbler(Consumer),它们共享一个列表。它们的创建就像第一个插入器,然后是咬者,然后是插入器等。每个实例都有一个带有参数(list,Runnable 线程)的构造函数,因此如果创建了一个实例,它将获取列表和最后创建的线程进行通信。

这意味着Nibbler得到(列表,(上次创建的)机械臂) 和插入器获取(列表,(上次创建的)啃食器)。

我希望 Nibbler 在他的运行方法开始时等待,以便下一个将 Nibbler 作为参数的插入器可以在他向列表中添加内容时通知他。我的问题是,它抛出了一个异常,我只是不明白为什么,或者我如何解决它。我将向您展示代码:

public class ListNibbler implements Runnable {
volatile List<Integer> list;
Runnable thread;
public ListNibbler(List<Integer> list, Runnable thread) {
this.list = list;
this.thread = thread;
}
@Override
public void run() {

// This is the critical code!
try {
this.getClass().wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

ListEL<Integer> element = null;

int random = (int) (Math.random() * list.getSize());

try {
while(list.getHead() == null) {
Thread.sleep(5);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

element = list.remove(random);
System.out.println(this + " eating " + element.val);
}

}

公共类 ListInserter 实现 Runnable{

volatile List<Integer> list;
Runnable thread;
public ListInserter(List<Integer> list, Runnable thread) {
this.list = list;
this.thread = thread;
}
@Override
public void run() {

int random = (int) (Math.random() * 1000);
try {
Thread.sleep(100);
System.out.println(this + " inserted " + random);
list.addElement(random);
}
catch (InterruptedException e) {
// nichts
}

// This is the critical code
thread.notify();
}

}

公共类列表{

// Erstes Element der verketteten Liste
private volatile ListEL<T> head;
// Die verkettete Liste, in der die ListEL-Objekte "gespeichert" werden
static volatile List<Integer> list = new List<>();
// Getter des Ersten Elements der Liste
public ListEL<T> getHead() {
return head;
}
// Setter des ersten Elements der Liste
public void setHead(ListEL<T> head) {
this.head = head;
}
// Added ein neues Element zur Liste
public void addElement(T value) {

// eine Kopie des ersten Elements wird erstellt
ListEL<T> element = head;

// Wenn das erste Element null ist, wird das hinzuzufügende Wert das erste Element (head) der Liste
if (getHead() == null) {
setHead(new ListEL<T>(value, null));
}
// Ansonsten wird element solange das nächste Element der Liste, bis das nächste null ist
else {
while(element.next != null) {
element = element.next;
}
// Hier wird dan das nächste Element des letzten Elements der Liste erstellt, mit dem hinzuzufügendem Wert
element.next = new ListEL<T>(value, null);
}
}
// Entfernt ein Element
public ListEL<T> remove(int index) {

ListEL<T> element = head;

if (index == 0) {
setHead(head.next);
return element;
}
else if (index < list.getSize() - 2) {
element = getElement(index);
list.getElement(index - 1).next = list.getElement(index + 1);
return element;
}
else {
element = getElement(index);
list.getElement(index - 1).next = null;
return element;
}
}
// Ermittelt das Element an dem gegebenem Index
public ListEL<T> getElement(int index) {

int count = 0;
ListEL<T> element = head;

while (count != index) {
element = element.next;
count++;
}
return element;
}
// Ermittelt die Groesse der dezeitigen Kette
public int getSize() {

int size = 0;
ListEL<T> element = head;

if (head == null) {
return 0;
}
else {
while (element.next != null) {
element = element.next;
size++;
}
return size;
}
}
public List() {
head = null;
}
public static void main(String[] args) {

Thread inserter = new Thread(new ListInserter(list, null));
inserter.start();


for (int i = 0; i < 19; i++) {
Thread nibbler = new Thread(new ListNibbler(list, inserter));
inserter = new Thread(new ListInserter(list, nibbler));

inserter.start();
nibbler.start();
}

Thread nibbler = new Thread(new ListNibbler(list, inserter));
nibbler.start();
}

}

好的。首先,这很糟糕:

this.getClass().wait();

它表示您尚未阅读有关等待的文档。如果你有,你会知道你需要同步你所说的等待,通知或通知全部打开。

// This is the critical code
thread.notify();

这也非常糟糕。几年前(在我被烧伤之后),我让他们更新 Javadocs 以指示线程内部使用 wait() 并通知/all 进行线程连接。由于副作用,您应该(几乎)永远不要在线程上调用等待,通知或通知所有内容。

这是通过等待,通知和通知所有进行生产者/消费者的方法

List <T> sharedList = ...;
public class Producer<T> implements Runnable {
List<T> list;
boolean running = true;
public Producer(List l) {
list = l;
}
public void run() {
while (running) {
Thread.sleep(someRandomValue);
synchronized(list) {
//add something to the list
list.notify();
}
}
}
public class Consumer<T> implements Runnable{
List<T> list;
boolean running = true;
public Consumer(List<T> l) {
list = l;
}
public void run() {
while (running) {
synchronized(list) {
while (list.size() > 0) {
//consume the value on the list
}
list.wait();
}
}
}
}

您可能还需要查看volatile关键字,因为有时在多线程中您希望将变量标记为这样。

最新更新