在线程中使用静态var作为不同实例之间的通信

时间:2012-09-05 05:11:02

标签: java thread-safety

我有一个多线程批处理应用程序,可以在5到10个并发执行线程之间运行。他们的数据段经过精心切片,尽可能均匀分布,但当然,执行时间总是不同的。我想做的是在最后一个线程完成时调用最后一种onFinalize方法,这将进行一些统计计算。

我想知道一个线程知道它是最后一个(而不是查询DB,这似乎是行人)的最佳方法是有一个静态var,当一个同步块时会增加一个静态var。每个线程完成时添加和减少新线程。因此,当一个线程完成并减少它时,我可以有一个if来查看未完成的线程数是否为0然后调用最终的统计数据。

这就是我的想法。我想知道是否有更好,更优雅或防弹的方式来实现这一目标。

使用Java 7

由于

4 个答案:

答案 0 :(得分:0)

为什么不在最后的每个线程上调用Thread.join()?你可以有一个for循环来调用它们 - 它会在第一次运行时锁定,然后当它完成时,返回然后你锁定下一次运行。当你退出循环时,他们都退出了。

public class ThreadManager {
    private List<Thread> threads;

    public void addThread(Thread thread) {
        threads.add(thread);
    }

    public void waitTillAllComplete() {
        for (int ind=0; ind<threads.size(); ind++)
            threads.get(ind).join();
    }
}

答案 1 :(得分:0)

我通过创建扩展基本Runnable接口的框架来提供类似的东西,以提供更强大的线程架构。后来我发现它与GWT中的异步代码非常相似,用于类似目的。

这是来自记忆,但它基本上归结为:

public interface AsyncRunnable<T> extends Runnable
{
    AsyncCallback<T> getCallback();

    T runAsync();
}

public interface AsyncCallback<T>
{
    void onSuccess(T data);
    void onFailure(Exception exception);
}

public interface AsyncCallbackInvoker<T> extends Runnable
{
    // implies requirement for callback...
    AsyncCallback<T> getCallback();
}

public class SuccessfulAsyncCallbackInvoker<T> implements AsyncCallback<T>
{
    private final AsyncCallback<T> callback;
    private final T data;

    public SuccessfulAsyncCallbackInvoker(AsyncCallback<T> callback, T data)
    {
        // note: data being null may be valid; callback would not be

        this.callback = callback;
        this.data = data;
    }

    @Override
    public void run()
    {
        callback.onSuccess(data);
    }

    @Override
    public AsyncCallback<T> getCallback()
    {
        return callback;
    }
}

public class FailureAsyncCallbackInvoker<T> implements AsyncCallback<T>
{
    private final AsyncCallback<T> callback;
    private final Exception  exception;

    public FailureAsyncCallbackInvoker(AsyncCallback<T> callback, Exception exception)
    {
        // note: data being null may be valid; callback would not be

        this.callback = callback;
        this.exception= exception;
    }

    @Override
    public void run()
    {
        callback.onFailure(exception);
    }

    @Override
    public AsyncCallback<T> getCallback()
    {
        return callback;
    }
}

public abstract class AbstractAsyncRunnable<T> implements AsyncRunnable<T>
{
    private final AsyncCallback<T> callback;

    public AbstractAsyncRunnable(AsyncCallback<T> callback)
    {
        // if == null -> throw

        this.callback = callback;
    }

    @Override
    public /* final */ void run()
    {
        AsyncCallbackInvoker<T> invoker;

        try
        {
            T data = runAsync();

            invoker = new SuccessfulAsyncCallbackInvoker<T>(callback, data);
        }
        catch (Exception e)
        {
            invoker = new FailureAsyncCallbackInvoker<T>(callback, e);
        }

        invokeCallback(invoker);
    }

    // allows overriding to put callback on whatever Thread you want
    protected void invokeCallback(AsyncCallbackInvoker<T> invoker)
    {
        invoker.run();
    }
}

实际上,它已被证明非常强大,特别是通过提供覆盖invokeCallback的能力,我们可以利用大量线程安全操作并保证响应。

在实践中,实现只需要覆盖runAsync的{​​{1}}方法,并提供他们认为合适的AsyncRunnable个方法。重要的是要注意,有时您真正使用它来简单地标记完成,在这种情况下,AsyncCallback可以是TVoid来自return null你使用那个)。

答案 2 :(得分:0)

所以你还可以做的是你可以创建一个ThreadManager类。这个类应该有一个List<Thread>。每当您创建新的Thread来执行任务时,您应register ThreadManager。然后在ThreadManager中创建一个方法,该方法返回numberlive Threads的总List

通过这种方式,您可以随时查看正在运行的线程数,还可以根据需要对正在运行的线程执行任何其他操作。还应该定期运行一个Thread,这应该清除List中所有死亡的线程引用。

示例ThreadManager可能如下所示:

public class ThreadManager {
    private static ThreadManager tm;
    private List<Thread> threads;

    public static ThreadManager get() {
        if(null == tm) {
            tm = new ThreadManager();
        }

        return tm;
    }

    private ThreadManager() {
        threads = new ArrayList<Thread>();
    }

    public int getCountOfAliveThreads() {
        int count = 0;
        for(Thread t : threads) {
            if(t.isAlive()) {
                count++;
            }
        }

        return count;
    }
}

希望这会有所帮助。您可以在Thread List上执行其他功能。

答案 3 :(得分:-1)

我很欣赏所有超级有用和启发性的答案,然而,带静态和易失性的简单计数器似乎工作正常:

private static volatile int crntThrdCnt = 0;

然后

    @Override
public void run() 
{
    crntThrdCnt++;
    this.runBatchInstance();
    crntThrdCnt--;

    if(crntThrdCnt == 0)
    {
        ProcessManager prcsMgr = new ProcessManager();
        Batch batch = prcsMgr.getBatch(this.batchID);
        batch.setEndTime(new Date());
        prcsMgr.updateBatch(batch);
    }
}