核心类库_多线程

多线程技术概述

线程与进程

进程

  • 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间

线程

  • 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行。一个进程最少有一个线程
  • 线程实际上是在进程基础之上进一步划分,一个进程启动之后,里面的若干执行路径又可以划分为若干个进程

线程池(Executors)

  如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
线程池的好处
  • 降低资源消耗
  • 提高响应速度
  • 提高线程的可管理性

Java中的四种线程池 .ExecutorService

1.缓存线程池

 1 /**
 2  * 缓存线程池.
 3  * (长度无限制)
 4  * 执行流程:
 5  *      1. 判断线程池是否存在空闲线程
 6  *      2. 存在则使用
 7  *      3. 不存在,则创建线程 并放入线程池, 然后使用
 8  */
 9 
10 ExecutorService service=Executors.newCachedThreadPool();
11 //向线程池中 加入 新的任务
12 service.execute(new Runnable() {
13     @Override public void run(){
14         System.out.println("线程的名称:"+Thread.currentThread().getName());
15     }
16 });
17 service.execute(new Runnable() { 
18     @Override public void run(){ 
19         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
20     } 
21 });
22 service.execute(new Runnable() { 
23     @Override public void run(){ 
24         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
25     } 
26 });

2.定长线程池

 1 /**
 2  * 定长线程池.
 3  * (长度是指定的数值)
 4  * 执行流程:
 5  *      1. 判断线程池是否存在空闲线程
 6  *      2. 存在则使用
 7  *      3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
 8  *      4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
 9  */
10 ExecutorService service = Executors.newFixedThreadPool(2); 
11 service.execute(new Runnable() { 
12     @Override public void run() { 
13         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
14     } 
15 }); 
16 service.execute(new Runnable() { 
17     @Override public void run() { 
18         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
19     } 
20 });

3.单线程线程池

 1 /**
 2  * 效果与定长线程池 创建时传入数值1 效果一致.
 3  * 单线程线程池.
 4  * 执行流程:
 5  * 1. 判断线程池的那个线程是否空闲
 6  * 2. 空闲则使用
 7  * 3. 不空闲,则等待池中的单个线程空闲后使用
 8  */
 9 ExecutorService service = Executors.newSingleThreadExecutor(); 
10 service.execute(new Runnable() { 
11     @Override public void run() { 
12         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
13     } 
14 }); 
15 service.execute(new Runnable() { 
16     @Override public void run() { 
17         System.out.println("线程的名称:"+Thread.currentThread().getName()); 
18     } 
19 });

4.周期性任务定长线程池

 1 public static void main(String[] args) {
 2         /**
 3          * 周期任务 定长线程池.
 4          * 执行流程:
 5          *      1. 判断线程池是否存在空闲线程
 6          *      2. 存在则使用
 7          *      3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
 8          *      4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
 9          *
10          * 周期性任务执行时:
11          *      定时执行, 当某个时机触发时, 自动执行某任务 .
12          */
13         ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
14         /**
15          * 定时执行
16          * 参数1. runnable类型的任务
17          * 参数2. 时长数字
18          * 参数3. 时长数字的单位
19          */
20         /*service.schedule(new Runnable() {
21             @Override public void run() {
22                 System.out.println("俩人相视一笑~ 嘿嘿嘿");
23             }
24         },5,TimeUnit.SECONDS);*/
25         /**
26          * 周期执行
27          * 参数1. runnable类型的任务
28          * 参数2. 时长数字(延迟执行的时长)
29          * 参数3. 周期时长(每次执行的间隔时间)
30          * 参数4. 时长数字的单位
31          */
32         service.scheduleAtFixedRate(new Runnable() {
33             @Override
34             public void run() {
35                 System.out.println("俩人相视一笑~ 嘿嘿嘿");
36             }
37         }, 5, 2, TimeUnit.SECONDS);
38     }

Runnable与Callable

 1 /**
 2      * 接口定义
 3      */
 4     //Callable接口
 5     public interface Callable<V> {
 6         V call() throws Exception;
 7     }
 8     //Runnable接口
 9     public interface Runnable {
10         public abstract void run();
11     }

Callable使用步骤

1. 编写类实现Callable接口 , 实现call方法
1 class XXX implements Callable<T> {
2         @Override public <T> call() throws Exception {
3             return T;
4         }
5     }
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
1 FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread,启动线程
1 new Thread(future).start();

Runnable与callable相同点

  • 都是接口
  • 都可以编写多线程程序
  • 都采用Thread.start()启动程序

Runnable与Callable不同点

  • Runnable没有返回值;Callable可以返回执行结果
  • Callable接口的call()允许抛出异常;Runnable的run()不能抛出
Callable获取返回值
  Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
原文地址:https://www.cnblogs.com/zhangzhongkun/p/14472757.html