多线程基础回顾(一)-线程创建
线程创建
1.继承Thread类,重写run()
缺点:无法继承其他类;
2.实现Runable接口,实现run()
优点:
- 解决了第一种方式的局限性;
- 适合多个相同的程序代码的线程去处理同一个资源
- 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
3.使用ExecutorService、Callable、Future实现有返回结果的多线程
优点:可返回结果,可抛出异常,可继承其他类; 缺点:步骤相对前者复杂;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //实现Callable接口,实现call(); 2 public class myThread implements Callable<String>{ 3 private String name; 4 public ThreadTest(String name) { 5 this.name = name; 6 } 7 @Override 8 public String call() throws Exception { 9 return name+"==>返回结果"; 10 } 11 12 public static void main(String[] args) { 13 //创建 Callable 实现类的实例, 14 myThread dog = new myThread("小狗"); 15 myThread cat = new myThread("小猫"); 16 //使用 FutureTask 类来包装 Callable 对象 17 FutureTask<String> task1 = new FutureTask<String>(dog); 18 FutureTask<String> task2 = new FutureTask<String>(cat); 19 //使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程 20 Thread thread1 = new Thread(task1,"线程1"); 21 Thread thread2 = new Thread(task2,"线程2"); 22 thread1.start(); 23 thread2.start(); 24 try { 25 //调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值 26 System.out.println(task1.get()); 27 System.out.println(task2.get()); 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } catch (ExecutionException e) { 31 e.printStackTrace(); 32 } 33 } 34 }
4.通过线程池方式:
优点:提高线程利用率,减少过多线程创建、销毁的损耗。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ThreadTest { 2 public static void main(String[] args) { 3 //创建线程池 4 ExecutorService ser = Executors.newFixedThreadPool(2); 5 //创建任务 6 ser1.execute(new Runnable() { 7 @Override 8 public void run() { 9 System.out.println("小鸡"); 10 } 11 }); 12 13 //创建有返回结果的任务(通过Callable实例) 14 Future<String> rs = ser1.submit(new Callable<String>() { 15 @Override 16 public String call() throws Exception { 17 return "haha"; 18 } 19 }); 20 21 try { 22 //get()获取返回结果 23 System.out.println(result1.get()); 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } catch (ExecutionException e) { 27 e.printStackTrace(); 28 } 29 //关闭线程池 30 ser.shutdown(); 31 //此时线程未必即刻关闭,若需要等线程池关闭后执行某些逻辑,通过awaitTermination()阻塞等待 32 try { 33 while(!ser1.awaitTermination(1000, TimeUnit.MILLISECONDS)) { 34 System.out.println("等待线程池关闭"); 35 } 36 System.out.println("线程池已关闭"); 37 } catch (InterruptedException e) { 38 e.printStackTrace(); 39 } 40 41 } 42 }
使用线程池记得最后关闭线程池
- shutdown():修改状态为SHUTDOWN,interrupt空闲线程,不影响正在运行的线程逻辑,对于新提交的线程抛出rejectedExecution异常。所以使用shutdown()关闭线程,需要确保线程不存在永久阻塞,否则线程池将关闭不了。
- shundownNow():强制关闭线程,修改状态为STOP,给与线程池内所有工作线程interrupt标志。所以若线程处于阻塞状态,抛出InterruptedException异常,否则执行完线程逻辑。所以使用shundownNow()注意对任务捕捉异常。
- shutdownNow()和shuwdown()调用完,线程池并不是立马就关闭了。若需要等待线程池关闭后做某些事需要使用awaitTermination()。
- awaitTermination(long timeout,TimeUnit unit):等待timeout后检测线程池是否关闭,返回结果是线程池是否已停止,返回true表示状态为terminated ,所有线程结束线程池已关闭;返回false,表示超时,线程池未关闭。