在这种多线程情况下,有哪些好的同步策略?

时间:2013-03-01 18:47:30

标签: java multithreading synchronization

我有两个主线程。一个产生新线程,另一个产生结果,如下所示:

//Spawner
while(!done) {
    spawnNewProcess(nextId, parameters);

    myListener.listenFor(nextId);

    nextId ++;
}

spawnNewProcess方法需要大量可变的时间。完成后,它会将结果对象放入可由Id访问的地图中。

侦听器线程运行如下:

//Listener
while(!done) {
    for (int id : toListenFor) {
        if (resultMap.contains(id)) {
            result = resultMap.get(id);

            toListenFor.remove(id);

            process(result);
        }
    }
}

我无法更改spawnNewProcess方法,也无法更改结果的存储方式。我想要做的是设置一个可以同时进行的最大限制。我的第一个倾向是只有一个可变曲目的数字。如果超过最大值,则生成器等待。当结果返回时,监听器将通知它。像这样:

//Spawner2

AtomicInteger numSpawns = new AtomicInteger(0);
int maxSpawns = 10;

while(!done) {
    if (numSpawns.intValue() >= maxSpawns) {
        this.wait(0);
    }
    numSpawns.getAndIncrement;

    spawnNewProcess(nextId, parameters);

    myListener.listenFor(nextId);

    nextId ++;
}

听众是:

//Listener2
while(!done) {
    for (int id : toListenFor) {
        if (resultMap.contains(id)) {
            result = resultMap.get(id);

            toListenFor.remove(id);

            numSpawns.getAndDecrement();
            Spawner.notify();

            process(result);
        }
    }
}

这会有用吗?是否存在我错过的潜在僵局?如果不知何故11或9个生成器同时运行而不是10个,那将不会是一个大问题。还是有一个更好的方式,我没有注意到?

2 个答案:

答案 0 :(得分:2)

使用Semaphore

import java.util.concurrent.Semaphore;
private Semaphore sem = new Semaphore(NUM_MAX_CONCURRENT);

// Spawner
while(!done) {

    sem.acquire(); // added by corsiKa

    spawnNewProcess(nextId, parameters);

    myListener.listenFor(nextId);

    nextId ++;
}

// listener
while(!done) {
    for (int id : toListenFor) {
        if (resultMap.contains(id)) {
            result = resultMap.get(id);

            toListenFor.remove(id);
            sem.release(); // added by corsiKa
            process(result);
        }
    }
}

答案 1 :(得分:0)

要控制正在运行的生成器的数量,请使用Executors.newFixedThreadPool(size),它将始终运行不超过固定数量的任务。然后将产卵任务包装在Runnable中并将其传递给ExecutorService

while(!done) {
    task = new Runnable() { public void run() {
        spawnNewProcess(nextId, parameters);
    } });

    exec.submit(task);;

    nextId ++;
}

要获得结果,请使用SynchronousQueueConcurrentLinkedQueue,这将允许您在线程之间传递对象,而不使用较低级别的并发对象。