时间:2021-05-20
在使用多线程的时候有时候我们会使用 java.util.concurrent.Executors的线程池,当多个线程异步执行的时候,我们往往不好判断是否线程池中所有的子线程都已经执行完毕,但有时候这种判断却很有用,例如我有个方法的功能是往一个文件异步地写入内容,我需要在所有的子线程写入完毕后在文件末尾写“---END---”及关闭文件流等,这个时候我就需要某个标志位可以告诉我是否线程池中所有的子线程都已经执行完毕,我使用这种方式来判断。
public class MySemaphore { public static void main(String[] args) throws IOException, InterruptedException { final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); final OutputStream os = new FileOutputStream(stream); final OutputStreamWriter writer = new OutputStreamWriter(os); final Semaphore semaphore = new Semaphore(10); ExecutorService exec = Executors.newCachedThreadPool(); final long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { final int num = i; Runnable task = new Runnable() { @Override public void run() { try { semaphore.acquire(); writer.write(String.valueOf(num)+"\n"); semaphore.release(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.submit(task); } exec.shutdown(); while(true){ if(exec.isTerminated()){ writer.write("---END---\n"); writer.close(); System.out.println("所有的子线程都结束了!"); break; } Thread.sleep(1000); } final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); }}当调用ExecutorService.shutdown方法的时候,线程池不再接收任何新任务,但此时线程池并不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。在调用shutdown方法后我们可以在一个死循环里面用isTerminated方法判断是否线程池中的所有线程已经执行完毕,如果子线程都结束了,我们就可以做关闭流等后续操作了。
判断线程池中的线程是否全部执行完毕的另外一种解决方案则是使用闭锁(CountDownLatch)来实现,CountDownLatch是一种灵活的闭锁实现,它可以使一个或多个线程等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,即表示需要等待的事情都已经发生。可以使用闭锁来这样设计程序达到目的:
public class CountDownLatchApproach { public static void main(String[] args) throws IOException, InterruptedException { final int nThreads = 10; final CountDownLatch endGate = new CountDownLatch(nThreads); final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); final OutputStream os = new FileOutputStream(stream); final OutputStreamWriter writer = new OutputStreamWriter(os); ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < nThreads; i++) { final int num = i; Runnable task = new Runnable() { @Override public void run() { try { writer.write(String.valueOf(num)+"\n"); } catch (IOException e) { e.printStackTrace(); } finally { endGate.countDown(); } } }; exec.submit(task); } endGate.await(); writer.write("---END---\n"); writer.close(); }}这种解决方案虽然可以达到目的但是性能差到没朋友,我更倾向于使用第一种方案。
现在我们有了更优雅的第三种方案,它的执行性能也不错。
public class MySemaphore { public static void main(String[] args) throws IOException, InterruptedException { final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); final OutputStream os = new FileOutputStream(stream); final OutputStreamWriter writer = new OutputStreamWriter(os); final Semaphore semaphore = new Semaphore(10); ExecutorService exec = Executors.newCachedThreadPool(); final long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { final int num = i; Runnable task = new Runnable() { @Override public void run() { try { semaphore.acquire(); writer.write(String.valueOf(num)+"\n"); semaphore.release(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.submit(task); } exec.shutdown(); exec.awaitTermination(1, TimeUnit.HOURS); writer.write("---END---\n"); writer.close(); System.out.println("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡"); final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); }}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
从Java5开始,Java提供了自己的线程池。线程池就是一个线程的容器,每次只执行额定数量的线程。java.util.concurrent.ThreadPool
Java程序有的时候在主线程中会创建多个线程去执行任务,然后在主线程执行完毕之前,把所有线程的任务进行汇总,以前可以用线程的join方法,但是这个方法不够灵
详解Java线程池和Executor原理的分析线程池作用与基本知识在开始之前,我们先来讨论下“线程池”这个概念。“线程池”,顾名思义就是一个线程缓存。它是一个或
前言定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行。但定时器线程池也还是线程池,最底层实现还是ThreadPoolExecutor,可以参
在java里,我们可以使用Executors.newFixedThreadPool来创建线程池,然后就可以不停的创建新任务,并用线程池来执行了。在提交任务时,如