创建和运行线程
方法一,直接使用 Thread
1. // 创建线程对象 2. Thread t = new Thread() { 3. public void run() { 4. // 要执行的任务 5. } 6. }; 7. // 启动线程 8. t.start();
例如:
1. // 构造方法的参数是给线程指定名字,推荐 2. Thread t1 = new Thread("t1") { 3. @Override 4. // run 方法内实现了要执行的任务 5. public void run() { 6. log.debug("hello"); 7. } 8. }; 9. t1.start();
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
- Thread 代表线程
- Runnable 可运行的任务(线程要执行的代码)
1. Runnable runnable = new Runnable() { 2. public void run() { 3. // 要执行的任务 4. } 5. }; 6. // 创建线程对象 7. Thread t = new Thread(runnable); 8. // 启动线程 9. t.start();
例如:
1. public class Test2 { 2. public static void main(String[] args) { 3. //创建线程任务 4. Runnable r = () -> { 5. //直接写方法体即可 6. System.out.println("Runnable running"); 7. System.out.println("Hello Thread"); 8. }; 9. //将Runnable对象传给Thread 10. Thread t = new Thread(r); 11. //启动线程 12. t.start(); 13. } 14. }
方法三:使用FutureTask与Thread结合
使用FutureTask可以用泛型指定线程的返回值类型(Runnable的run方法没有返回值)
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
1. // 创建任务对象 2. FutureTask<Integer> task3 = new FutureTask<>(() -> { 3. log.debug("hello"); 4. return 100; 5. }); 6. // 参数1 是任务对象; 参数2 是线程名字,推荐 7. new Thread(task3, "t3").start(); 8. // 主线程阻塞,同步等待 task 执行完毕的结果 9. Integer result = task3.get(); 10. log.debug("结果是:{}", result);
1. public class Test3 { 2. public static void main(String[] args) throws ExecutionException, InterruptedException { 3. //需要传入一个Callable对象 4. FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() { 5. @Override 6. public Integer call() throws Exception { 7. System.out.println("线程执行!"); 8. Thread.sleep(1000); 9. return 100; 10. } 11. }); 12. 13. Thread r1 = new Thread(task, "t2"); 14. r1.start(); 15. //获取线程中方法执行后的返回结果 16. System.out.println(task.get()); 17. } 18. }
方式四:使用线程池例如用Executor框架
参数介绍
1. public ThreadPoolExecutor(int corePoolSize, 2. int maximumPoolSize, 3. long keepAliveTime, 4. TimeUnit unit, 5. BlockingQueue<Runnable> workQueue, 6. ThreadFactory threadFactory, 7. RejectedExecutionHandler handler) { 8. if (corePoolSize < 0 || 9. maximumPoolSize <= 0 || 10. maximumPoolSize < corePoolSize || 11. keepAliveTime < 0) 12. throw new IllegalArgumentException(); 13. if (workQueue == null || threadFactory == null || handler == null) 14. throw new NullPointerException(); 15. this.acc = System.getSecurityManager() == null ? 16. null : 17. AccessController.getContext(); 18. this.corePoolSize = corePoolSize; 19. this.maximumPoolSize = maximumPoolSize; 20. this.workQueue = workQueue; 21. this.keepAliveTime = unit.toNanos(keepAliveTime); 22. this.threadFactory = threadFactory; 23. this.handler = handler; 24. }
* @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set
池中一直保持的线程的数量,即使线程空闲也不会释放。除非设置了 allowCoreThreadTimeOut *
@param maximumPoolSize the maximum number of threads to allow in the * pool
池中允许的最大的线程数
* @param keepAliveTime when the number of threads is greater than * the core, this is the maximum time that excess idle threads * will wait for new tasks before terminating.
当线程数大于核心线程数的时候,线程在最大多长时间没有接到新任务就会终止释放, 最终线程池维持在 corePoolSize 大小
* @param unit the time unit for the {@code keepAliveTime} argument
时间单位
* @param workQueue the queue to use for holding tasks before they are* executed. This queue will hold only the {@code Runnable} * tasks submitted by the {@code execute} method.
阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了 corePoolSize
大小,就会放在这里等待空闲线程执行。
* @param threadFactory the factory to use when the executor * creates a new thread
创建线程的工厂,比如指定线程名等
* @param handler the handler to use when execution is blocked * because the thread bounds and queue capacities are reached
拒绝策略,如果线程满了,线程池就会使用拒绝策略
运行原理:
1、线程池创建,准备好 core 数量的核心线程,准备接受任务
2、新的任务进来,用 core 准备好的空闲线程执行。
(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队 列获取任务执行
(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
(3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自 动销毁。最终保持到 core 大小
(4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策 略进行处理
3、所有的线程创建都是由指定的 factory 创建的。