线程池(⼀)线程池的基本使⽤
⼀、线程池简介
线程池的概念
线程池就是⾸先创建⼀些线相衬,它们的集合称为线程池,使⽤线程池可以很好的提⾼性能,线程池在系统启动时既创建⼤量空闲的线程,程序将⼀个任务传给线程池。线程池就会启动⼀条线程来执⾏这个任务,执⾏结束后,该线程并不会死亡,⽽是再次返回线程池中成为空闲状态,等待执⾏下⼀个任务。
线程池的⼯作机制
在线程池的编程模式下,任务是提交给整个线程池,⽽不是直接提交给某个线程,线程池在拿到任务后,就在内部寻是否有空闲的线程,如果有,则将任务交给某个空闲的线程
⼀个线程同时只能执⾏⼀个任务,但可以同时向⼀个线程池提交多个任务
使⽤线程池的原因
多线程运⾏时间,系统不断的启动和关闭新线程,成本⾮常⾼,会过度消耗系统资源,以及过渡切换线程的危险,从⽽导致系统资源的崩溃,这时,线程池也就是最好的选择了。
⼆、四种常见的线程池详解
线程池的返回值ExecutorService简介
ExecutorService是Java提供的⽤于管理线程池的类。该类的两个作⽤:控制线程数量和重⽤线程
具体的4种常⽤的线程池实现
1. newCachedThreadPool:创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线
程。
2. newFixedThreadPool:创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
3. newScheduledThreadPool:创建⼀个定长线程池,⽀持定时及周期性任务执⾏。
4. newSingleThreadExecutor:创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO,
LIFO, 优先级)执⾏
创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。
⽰例代码如下:
//创建可缓存线程池
ExecutorService cachedThreadPool = wCachedThreadPool();
for(int i =0; i <10; i++){
try{
//sleep可明显看到使⽤的是线程池⾥⾯以前的线程,没有创建新的线程
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
@Override
public void run(){
//打印正在执⾏的缓存线程信息
System.out.println(Thread.currentThread().getName()+"正在被执⾏1");
}
});
}
}
}
线程池为⽆限⼤,当执⾏第⼆个任务时第⼀个任务已经完成,会复⽤执⾏第⼀个任务的线程,⽽不⽤每次新建线程。
创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
执⾏⽰例代码如下:
//创建⼀个可重⽤固定个数的线程池
ExecutorService fixedThreadPool = wFixedThreadPool(3);
for(int i =0; i <10; i++){
@Override
public void run(){
try{
//打印正在执⾏的缓存线程信息
System.out.println(Thread.currentThread().getName()+"正在被执⾏");
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
}
}
}
因为线程池⼤⼩为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。java线程池创建的四种
定长线程池的⼤⼩最好根据系统资源进⾏设置。如Runtime().availableProcessors()。可参考PreloadDataCache。
创建⼀个定长线程池,⽀持定时及周期性任务执⾏。
延迟执⾏⽰例代码如下:
public class ThreadPoolExecutorDemo {
public static void main(String[] args){
//创建⼀个定长线程池,⽀持定时及周期性任务执⾏——延迟执⾏
ScheduledExecutorService scheduledThreadPool = wScheduledThreadPool(5);
//延迟1秒执⾏
scheduledThreadPool.schedule(new Runnable(){
@Override
public void run(){
System.out.println("延迟5秒执⾏");
}
},5, TimeUnit.SECONDS);
}
}
表⽰延迟5秒执⾏。
定期执⾏⽰例代码如下:
//创建⼀个定长线程池,⽀持定时及周期性任务执⾏——延迟执⾏
ScheduledExecutorService scheduledThreadPool = wScheduledThreadPool(5);
//延迟1秒执⾏
scheduledThreadPool.scheduleAtFixedRate(new Runnable(){
@Override
public void run(){
System.out.println("延迟1秒后每3秒执⾏⼀次");
}
},1,3, TimeUnit.SECONDS);
}
}
表⽰延迟1秒后每3秒执⾏⼀次
TimeUnit类
TimeUnit.DAYS //天
TimeUnit.HOURS //⼩时
TimeUnit.MINUTES //分钟
TimeUnit.SECONDS //秒
TimeUnit.MILLISECONDS //毫秒
创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。⽰例代码如下:
public class ThreadPoolExecutorDemo {
public static void main(String[] args){
//创建⼀个单线程化的线程池
ExecutorService singleThreadExecutor = wSingleThreadExecutor();
for(int i =0; i <10; i++){
final int index = i;
@Override
public void run(){
try{
//结果依次输出,相当于顺序执⾏各个任务
System.out.println(Thread.currentThread().getName()+"正在被执⾏,打印的值是:"+index);
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
}
}
}
三、缓冲队列BlockingQueue和⾃定义线程池ThreadPoolExecutor
缓冲队列BlockingQueue简介:
BlockingQueue是双缓冲队列。BlockingQueue内部使⽤两条队列,允许两个线程同时向队列⼀个存储,⼀个取出操作。在保证并发安全的同时,提⾼了队列的存取效率。
常⽤的⼏种BlockingQueue:
1. ArrayBlockingQueue(int i):规定⼤⼩的BlockingQueue,其构造必须指定⼤⼩。其所含的对象是FIFO顺序排序的。
2. LinkedBlockingQueue()或者(int i):⼤⼩不固定的BlockingQueue,若其构造时指定⼤⼩,⽣成的BlockingQueue有⼤⼩限
制,不指定⼤⼩,其⼤⼩有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。
3. PriorityBlockingQueue()或者(int i):类似于LinkedBlockingQueue,但是其所含对象的排序不是FIFO,⽽是依据对象的⾃然
顺序或者构造函数的Comparator决定。
4. SynchronizedQueue():特殊的BlockingQueue,对其的操作必须是放和取交替完成。
⾃定义线程池(ThreadPoolExecutor和BlockingQueue连⽤)
⾃定义线程池,可以⽤ThreadPoolExecutor类创建,它有多个构造⽅法来创建线程池。
常见的构造函数:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
⽰例代码:
public class TempThread implements Runnable{
@Override
public void run(){
// 打印正在执⾏的缓存线程信息
System.out.println(Thread.currentThread().getName()+"正在被执⾏");
try{
// sleep⼀秒保证3个任务在分别在3个线程上执⾏
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论