善于思考,拥抱变化,才能拥有未来
一、Threads 和 Runnables
1 public void researchThread(){ 2 Runnable task = () -> { 3 String threadName = Thread.currentThread().getName(); 4 System.out.println("Hello " + threadName); 5 }; 6 7 task.run(); 8 9 Thread thread = new Thread(task); 10 thread.start(); 11 12 System.out.println("Done!"); 13 }
运行结果为:
Hello main
Done!
Hello Thread-0
或者:
Hello main
Hello Thread-0
Done!
也可以在线程调用时,加入线程休眠来观察线程调用流程。
TimeUnit.SECONDS.sleep(1);
二、ExecutorService
1. newSingleThreadExecutor
1 public static void getExceterService1(){ 2 ExecutorService executor = Executors.newSingleThreadExecutor(); 3 executor.submit(() -> { 4 String threadName = Thread.currentThread().getName(); 5 System.out.println("Hello " + threadName); 6 }); 7 }
2. 关闭executors
/** * shutdwon()会等待正在执行的任务执行完 * shutdownNow()止所有正在执行的任务并立即关闭execuotr */ public static void shutdownExcuterService2(){ ExecutorService executor = Executors.newSingleThreadExecutor(); try { System.out.println("attempt to shutdown executor"); executor.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); }catch (InterruptedException e) { System.err.println("tasks interrupted"); }finally { if (!executor.isTerminated()) { System.err.println("cancel non-finished tasks"); } executor.shutdownNow(); System.out.println("shutdown finished"); } }
3.callable提交线程任务-newFixedThreadPool
public static void testCallable1() throws ExecutionException, InterruptedException { Callable<Integer> task = () -> { try { TimeUnit.SECONDS.sleep(1); return 123; } catch (InterruptedException e) { throw new IllegalStateException("task interrupted", e); } }; ExecutorService executor = Executors.newFixedThreadPool(1); Future<Integer> future = executor.submit(task); System.out.println("future done? " + future.isDone()); Integer result = future.get(); System.out.println("future done? " + future.isDone()); System.out.print("result: " + result); }
执行结果为:
future done? false
future done? true
result: 123
注:关闭executor,所有的未中止的future都会抛出异常。
4. 任何future.get()
调用都会阻塞,然后等待直到callable中止。在最糟糕的情况下,一个callable持续运行——因此可以简单的传入一个时长来避免这种情况。
1 public void getTimeoutException() throws InterruptedException, ExecutionException, TimeoutException { 2 ExecutorService executor = Executors.newFixedThreadPool(1); 3 4 Future<Integer> future = executor.submit(() -> { 5 try { 6 TimeUnit.SECONDS.sleep(2); 7 return 123; 8 } 9 catch (InterruptedException e) { 10 throw new IllegalStateException("task interrupted", e); 11 } 12 }); 13 14 future.get(1, TimeUnit.SECONDS); 15 }
会抛出异常:
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:205)
at com.example.junit.concurrent.LearnCallable.getTimeoutException(LearnCallable.java:51)
at com.example.junit.concurrent.LearnCallable.main(LearnCallable.java:99)
5. invokeAll
1 public void testInvokeAll() throws InterruptedException { 2 ExecutorService executor = Executors.newWorkStealingPool(); 3 4 List<Callable<String>> callables = Arrays.asList( 5 () -> "task1", 6 () -> "task2", 7 () -> "task3"); 8 9 executor.invokeAll(callables) 10 .stream() 11 .map(future -> { 12 try { 13 return future.get(); 14 } 15 catch (Exception e) { 16 throw new IllegalStateException(e); 17 } 18 }) 19 .forEach(System.out::println); 20 }
6.invokeAny-在等待future对象的过程中,这个方法将会阻塞直到第一个callable中止然后返回这一个callable的结果。
1 public void testInvokeAny() throws ExecutionException, InterruptedException { 2 3 ExecutorService executor = Executors.newWorkStealingPool(); 4 5 List<Callable<String>> callables = Arrays.asList( 6 callable("task1", 2), 7 callable("task2", 1), 8 callable("task3", 3)); 9 10 String result = executor.invokeAny(callables); 11 System.out.println(result); 12 13 } 14 15 private Callable<String> callable(String result, long sleepSeconds) { 16 return () -> { 17 TimeUnit.SECONDS.sleep(sleepSeconds); 18 return result; 19 }; 20 }
7.ScheduledExecutorService
支持任务调度,持续执行或者延迟一段时间后执行。
1 public static void testScheduled() throws InterruptedException { 2 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 3 4 Runnable task = () -> System.out.println("Scheduling: " + System.nanoTime()); 5 ScheduledFuture<?> future = executor.schedule(task, 3, TimeUnit.SECONDS); 6 7 TimeUnit.MILLISECONDS.sleep(1337); 8 9 long remainingDelay = future.getDelay(TimeUnit.MILLISECONDS); 10 System.out.printf("Remaining Delay: %sms", remainingDelay); 11 }
executor.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
scheduleAtFixedRate()
并不考虑任务的实际用时。所以,如果你指定了一个period为1分钟而任务需要执行2分钟,那么线程池为了性能会更快的执行。
executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS);
scheduleWithFixedDelay()
在你不能预测调度任务的执行时长时是很有用的。