如何防止共享同一个对象?

时间:2016-11-11 00:11:44

标签: java multithreading producer-consumer

我的程序采用一个线程数组,它还包含一个" Queue"由我定义的课程,其中包括"工作"来自main()的对象并将它们推送到线程类中。

class Queue {
volatile boolean value = false;
int i;
Work[] WI;
public Queue(int num) {
    this.WI = new Work[num];
    this.i = 0;
    }
synchronized void enqueue(Work WI) {
    if (value) {
        try {
            wait();} catch (Exception e) {
            System.out.println(e);
        }
    }
    this.WI[i++] = WI;
    value = true;
    notify();
}
synchronized Work dequeue() {
    if (!value) {
        try {
            wait();} catch (Exception e) {
            System.out.println(e);
        }
    }
    value = false;
    notify();
    return this.WI[i - 1];
 }
}

这是我的Thread课程" Work"对象和计算。

class Thread_Produce implements Runnable {

Work WI;
Queue q;
int row, column,n,s, start;
Thread t;
public Thread_Produce(Queue q,int n) {
    this.q = q;
    t = new Thread(this);
    this.n = n;
    this.s = 0;
    this.start = 0;
    t.start();
}

public void run() {
        for (int j = 0; j < n; j++) {
                this.WI = (Work) q.dequeue();
                for (int i = 0; i < WI.array1[0].length; i++) {
                    s = s + WI.array1[WI.row][i] * WI.array2[WI.column][i];
                }
                System.out.println(s);
                s = 0;
            }
}

但是我做了#34; Queue&#34;类方法同步我的线程数组共享相同&#34;工作&#34;对象来自&#34;队列&#34;。一个数组进入run方法而没有正确执行前一个方法。我该怎么办?

2 个答案:

答案 0 :(得分:1)

不要重新发明轮子,使用现有的轮子:

使用ConcurrentLinkedQueue作为您创建自己的队列。没有同步,它是100%线程安全的。

答案 1 :(得分:0)

您的代码如下:

if (condition)
    wait();

不起作用。 wait方法释放锁并将调用线程置于等待状态。一旦线程从等待中唤醒,它必须获得锁定才能使呼叫等待。但在那时,线程不知道状态是什么状态。接收通知并不能保证通知的线程可以立即获得锁定,其他一些线程可能已经在通知和获取锁定之间起作用。

相反,总是在循环中调用wait,这样当你的线程唤醒时,它会检查它一旦锁定就等待它的状态。请参阅Oracle教程,尤其是the Guarded Blocks page

此外,您还在两个单独的案例中使用通知。当线程被通知时,它被任意选择通知,它可能是相关的或不可能的,并且如果通知与正好接收它的线程相关,则该通知将丢失。使用notifyall,至少你知道它是否与任何等待的线程相关,然后它将被采取行动。

不要使用标志,只需检查数组中是否有任何内容。