在Replicated Workers范例中的更多线程上的随机结果

时间:2014-11-22 21:06:07

标签: java multithreading concurrency synchronized

我的代码如下:

WorkPool.java

import java.util.LinkedList;

/**
 * Class that implements a work pool based on the model of "replicated workers"
 * Tasks introduced in the work pool are objects of type MRCTask
 *
 */
public class WorkPool {
    int nThreads; //total number of worker threads
    int nWaiting = 0; //number of worker threads blocked waiting for a task
    public boolean ready = false; //problem is finished 

    LinkedList<MRCTask> tasks = new LinkedList<MRCTask>();

    /**
     * Constructor for class WorkPool.
     * @param nThreads - number of worker threads
     */
    public WorkPool(int nThreads) {

        this.nThreads = nThreads;

    }

    /**
     * Function which tries to obtain a task from the work pool
     * If there are not available tasks, the function hangs until
     * a task can be given or until the problem is finished
     * @return A task to solve or null if the problem is finished
     */
    public synchronized MRCTask getWork() {

        if (tasks.size() == 0) { //empty work pool
            nWaiting++;
            /*
             * finish condition:
             * there is no available task in the work pool and no worker
             * is active
             */
            if (nWaiting == nThreads) {
                ready = true;
                /* problem is finished, announcing all workers */
                notifyAll();
                return null;
            } else {
                while (!ready && tasks.size() == 0) {
                    try {
                        this.wait();
                    } catch(Exception e) {e.printStackTrace();}
                }

                if (ready)
                    /* work is done */
                    return null;

                nWaiting--;

            }
        }
        return tasks.remove();

    }

    /**
     * Function which inserts a task in the work pool
     * @param sp The task which must be introduced
     */
    synchronized void putWork(MRCTask sp) {

        tasks.add(sp);
        /* announcing one of the waiting workers */
        this.notify();

    }

}

TestMain.Java

public class TestMain {

public static void main(String[] args) throws InterruptedException {

    int nr_proc = Runtime.getRuntime().availableProcessors();
    WorkPool wp = new WorkPool(nr_proc);
    MRCTask.t = 0;
    for(int i = 0; i < 10000; i++)
        wp.putWork(new MRCTask());

    Worker[] wrk = new Worker[nr_proc];

    for(int i = 0; i < nr_proc; i++)
        wrk[i] = new Worker(wp);

    for(int i = 0; i < nr_proc; i++)
        wrk[i].start();

    for(int i = 0; i < nr_proc; i++)
        wrk[i].join();

    System.out.println(MRCTask.t);
}

}

class Worker extends Thread {

WorkPool wp;

public Worker(WorkPool wp) {

    this.wp = wp;

}

void work(MRCTask ps) throws Exception {

    ps.processTask();

}

public void run() {

    while (true) {
        MRCTask ps = wp.getWork();
        if (ps == null)
            break;          
        try {
            work(ps);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }

}

}

class MRCTask {

static int t;
public void processTask() {
    t += 5;
}

}

运行此代码时,我通常希望得到50000作为答案。这只发生在nr_proc为1时。当nr_proc为2或4时(在我的情况下,availableProcessor()返回4),我得到随机值,如49960,49900,49995,有时甚至50000。 你能告诉我有什么问题吗? 提前致谢并抱歉这个庞大的代码! PS:我试图修改函数processTask(),如下所示:

public void processTask() {
    synchronized(this) {
        t += 5;
    }
}

但是,我仍然遇到同样的问题。我认为同步部分会有所帮助,但他们没有。

1 个答案:

答案 0 :(得分:1)

您的值t是静态的。所以你试图同步事物的方式,注定要失败。实际上你没有同步任何东西,因为你有许多不同的MRCTask实例(实际上是10000)。他们每个人都有一个单独的锁/监视器。 尝试将MRCTask中的代码更改为:

private static final Object LOCK = new Object();

public void processTask() {
    synchronized (LOCK) {
        t += 5;
    }

}

这是不同的,现在您使用共享锁。 看看你是否仍然得到不可预测/随机的结果。你不会。 以前你只是有一个古典的竞争条件。