簡體   English   中英

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

[英]Java - Ideal use of wait and notify?

到目前為止,該代碼在測試中似乎可以正常工作。 但是,我是多線程技術的新手,並且想知道這段代碼是否理想,因為我知道關於並發性有很多“缺點”。
有沒有更好的方法在單個線程上為排隊的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();
    }
}

}

沒關系-ish。

最好不要重新發明輪子。

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()來停止使用者線程。

如果不停止線程,則除非它們是守護程序,否則程序將不會退出。

您為什么要自己實施? 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);

這里有一些改進...當然,如果您使用BlockingQueue / ExecutorService,我們無需擔心同步/並發性。

  1. 代碼中的一個主要問題是:“ r.run()”而不是新的Thread(r).start()。
  2. 使用ConcurrentLinkedQueue數據結構,該結構是線程安全的。
  3. 您可以在任何靜態obj / class obj上提供鎖定/通知,而不必在隊列中,因為隊列已經是線程安全的。
  4. 不需要隊列到陣列的轉換。 迭代queue.poll()。

另外,您還可以使用並發鎖API(ReentrantLock或Condition類),而不是同步/等待/通知。

theexamtime.com

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM