线程池(重要)
标准库中的线程池
•
使⽤ Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池.
•
返回值类型为 ExecutorService
•
通过 ExecutorService.submit 可以注册⼀个任务到线程池中
ExecutorService pool
= Executors.newFixedThreadPool(
10
);
pool.submit(
new
Runnable
() {
@Override
public void
run
() {
System.out.println(
"hello"
);
}
});
Executors 创建线程池的⼏种⽅式
•
newFixedThreadPool: 创建固定线程数的线程池
•
newCachedThreadPool: 创建线程数⽬动态增⻓的线程池.
•
newSingleThreadExecutor: 创建只包含单个线程的线程池.
•
newScheduledThreadPool: 设定 延迟时间后执⾏命令,或者定期执⾏命令. 是进阶版的 Timer.
Executors 本质上是 ThreadPoolExecutor 类的封装
面试问题
ThreadPoolExecutor 提供了更多的可选参数, 可以进⼀步细化线程池⾏为的设定.
•
corePoolSize: 正式员⼯的数量. (正式员⼯, ⼀旦录⽤, 永不辞退)
•
maximumPoolSize: 正式员⼯ + 临时⼯的数⽬. (临时⼯: ⼀段时间不⼲活, 就被辞退).
•
keepAliveTime: 临时⼯允许的空闲时间.
•
unit: keepaliveTime 的时间单位, 是秒, 分钟, 还是其他值.
•
workQueue: 传递任务的阻塞队列
•
(重要
)threadFactory: 创建线程的⼯⼚, 参与具体的创建线程⼯作. 通过不同线程⼯⼚创建出的线程相当于
对⼀些属性进⾏了不同的初始化设置.
1.RejectedExecutionHandler: 拒绝策略, 如果任务量超出公司的负荷了接下来怎么处理.
2.AbortPolicy(): 超过负荷, 直接抛出异常.
3.CallerRunsPolicy(): 调⽤者负责处理多出来的任务.
4.DiscardOldestPolicy(): 丢弃队列中最⽼的任务.
5.DiscardPolicy(): 丢弃新来的任务.
实现线程池
•
核⼼操作为 submit, 将任务加⼊线程池中
•
使⽤ Worker 类描述⼀个⼯作线程. 使⽤ Runnable 描述⼀个任务.
•
使⽤⼀个 BlockingQueue 组织所有的任务
•
每个 worker 线程要做的事情: 不停的从 BlockingQueue 中取任务并执⾏.
•
指定⼀下线程池中的最⼤线程数 maxWorkerCount; 当当前线程数超过这个最⼤值时, 就不再新增
线程
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; class MyThreadpool{ private BlockingQueue<Runnable> queue=null;/使⽤⼀个 BlockingQueue 组织所有的任务 //// 创建了⼀个固定数量的线程池 public MyThreadpool(int n){ //ArrayBlockingQueue为任务队列,容量为1000 queue=new ArrayBlockingQueue<>(1000); while(n>0){ Thread t=new Thread(()->{ while (true){ try { Runnable arr=queue.take();//使⽤ Runnable 描述⼀个任务. arr.run(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); n--; } } //使⽤ Runnable 描述⼀个任务. public void submit(Runnable stak) throws InterruptedException {/核⼼操作为 submit, 将任务加⼊线程池中 queue.put(stak); } } //线程池 public class work2 { public static void main(String[] args) throws InterruptedException { MyThreadpool per=new MyThreadpool(10); int i=0; for( i=0;i<100;i++){ int id=i; per.submit(()->{ System.out.println(Thread.currentThread().getName()+" id "+id); }); } } }
对⽐线程和进程
线程的优点
1.
创建⼀个新线程的代价要⽐创建⼀个新进程⼩得多
2.
与进程之间的切换相⽐,线程之间的切换需要操作系统做的⼯作要少很多
3.
线程占⽤的资源要⽐进程少很多
4.
能充分利⽤多处理器的可并⾏数量
5.
在等待慢速I/O操作结束的同时,程序可执⾏其他的计算任务
6.
计算密集型应⽤,为了能在多处理器系统上运⾏,将计算分解到多个线程中实现
7.
I/O密集型应⽤,为了提⾼性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
进程与线程的区别
1.
进程是系统进⾏资源分配和调度的⼀个独⽴单位,线程是程序执⾏的最⼩单位。
2.
进程有⾃⼰的内存地址空间,线程只独享指令流执⾏的必要资源,如寄存器和栈。
3.
由于同⼀进程的各线程间共享内存和⽂件资源,可以不通过内核进⾏直接通信。
4.
线程的创建、切换及终⽌效率更⾼。