Java - 等待和通知的理想用途?

时间:2014-01-03 16:00:21

标签: java multithreading wait notify executor

此代码似乎在测试中工作正常。但是我是多线程的新手,想知道这段代码是否理想,因为我知道有很多关于并发性的“傻瓜”。
有没有更好的方法在单个线程上为排队的Runnables创建执行程序?这是我第一次制作一个,所以我倾向于相信一些事情会更好。

public class ExplosionExecutor{
private static List<Runnable> queue= new ArrayList<Runnable>();

private static Thread thread= new Thread(new Runnable() {
    public void run() {
        while(true){
            Runnable[] queuedump;
            synchronized (queue) {
                if(queue.size()==0){
                    try {
                        queue.wait();
                    } catch (InterruptedException e){e.printStackTrace();}
                }

                queuedump= queue.toArray(new Runnable[0]);
                queue.clear();  
            }
            for(Runnable r : queuedump)
                r.run();
        }
    }

}, "Nuke Explosions");
static{
    thread.start();
}

public static void execute(Runnable command) {
    synchronized (queue) {
        queue.add(command);
        queue.notify();
    }
}

}

3 个答案:

答案 0 :(得分:1)

这没关系 - 是的。

最好不要重新发明轮子。

1)有阻塞队列有等待新项目的方法并且已经同步:

public static void main(String[] args) throws Exception {
    final BlockingQueue<Runnable> r = new LinkedBlockingQueue<>();
    final Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            while (true) {
                try {
                    r.take().run();
                } catch (InterruptedException ex) {
                    return;
                }
            }
        }
    });
    r.add(new Runnable() {

        @Override
        public void run() {
            //do stuff
        }
    });
}

2)ExecutorService API封装了所有这些行为:

public static void main(String[] args) throws Exception {
    final ExecutorService es = Executors.newSingleThreadExecutor();
    es.execute(new Runnable() {

        @Override
        public void run() {
            //do stuff
        }
    });
}

3)如果您想检查已提交任务的成功和/或等待结束的任务完成,则无法使用您的API执行此操作。使用ExecutorService,您可以非常轻松地完成此任务。

public static void main(String[] args) throws InterruptedException {
    final ExecutorService es = Executors.newSingleThreadExecutor();
    final Future<?> f = es.submit(new Runnable() {

        @Override
        public void run() {
            //do stuff
        }
    });
    try {
        //wait
        f.get();        
    } catch (ExecutionException ex) {
        //there was an exeception in the task
    }
}

最后要注意的是,您实现代码的方式无法阻止使用者线程。

在我的第一个示例中,您需要手动调用t.interrupt(),并且由于我的实现,这将导致线程退出。在第二个/第三个示例中,您需要调用ExecutorService.shutdown()来停止使用者线程。

如果你没有停止线程,那么你的程序将不会退出,除非它们是守护进程。

答案 1 :(得分:0)

为什么要自己实施? Java有一个内置的ExecutorService,可以在一个线程上运行Runnables http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html

//runs all Runnables in a single thread, one at a time
ExecutorService executor = Executors.newFixedThreadPool(1);

executor.submit(runnable);

答案 2 :(得分:0)

以下是一些改进......当然,如果您使用BlockingQueue / ExecutorService,我们不需要担心同步/并发。

  1. 代码中的一个主要问题是:“r.run()”而不是新的Thread(r).start()。
  2. 使用线程安全的ConcurrentLinkedQueue数据结构。
  3. 您可以提供对任何静态obj / class obj的锁定/通知,不需要在队列中,因为队列已经是线程安全的。
  4. 不需要队列到阵列转换。迭代为queue.poll()。
  5. 此外,您还可以使用并发锁API(ReentrantLock或Condition类)而不是synchronized / wait / notify。

    theexamtime.com