线程池
优势:
- 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗
- 提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行
- 方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率;
- 更强大的功能,线程池提供了定时、定期以及可控线程数等功能的线程池,使用方便简单。
创建线程池
ExectuorService es=Executors.线程池
几种不同的线程池
1、newCachedThreadPool()
创建一个可缓存的无界线程池,该方法无参数。当线程池中的线程空闲时间超过60s则会自动回收该线程,当任务超过线程池的线程数则创建新线程。线程池的大小上限为Integer.MAX_VALUE,可看做是无限大。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
cachedThreaPoolDemo();
}
public static void cachedThreaPoolDemo() {
ExecutorService cachedTP=Executors.newCachedThreadPool();
for(int i=0;i<5;i++) {
final int index=i;
cachedTP.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+",index="+index);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
2、newFixedThreadPool()
创建一个固定大小的线程池,该方法可指定线程池的固定大小,对于超出的线程会在LinkedBlockingQueue队列中等待。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
fixedThreaPoolDemo();
}
public static void fixedThreaPoolDemo() {
ExecutorService fixedTP=Executors.newFixedThreadPool(3);
for(int i=0;i<6;i++) {
final int index=i;
fixedTP.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+",index="+index);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3、newSingleThreadExecutor()
创建只有一个线程的线程池,该方法无参数,所有任务都保存队列LinkedBlockingQueue中,等待唯一的单线程来执行任务,并保证所有任务按照指定顺序执行。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
singleThreaPoolDemo();
}
public static void singleThreaPoolDemo() {
ExecutorService singleTP=Executors.newSingleThreadExecutor();
for(int i=0;i<3;i++) {
final int index=i;
singleTP.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+",index="+index);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4、newScheduleThreadPool()
创建一个可定时执行或周期执行任务的线程池,该方法可指定线程池的核心线程个数。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
scheduledThreaPoolDemo();
}
public static void scheduledThreaPoolDemo() {
ScheduledExecutorService scheduledTP=Executors.newScheduledThreadPool(3);
//定时执行一次的任务,延迟1s后执行
scheduledTP.schedule(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+",delay 1s");
}
}, 1, TimeUnit.SECONDS);
//周期性执行的任务,延迟2s后,每3s一次的周期性执行任务
scheduledTP.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+",every 3s");
}
}, 2, 3, TimeUnit.SECONDS);
}
}
5、newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行并且可定时或者延迟执行线程活动。
代码:
class Run implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
public static void main(String[] args) {
ExecutorService es=Executors.newCachedThreadPool();
Run r=new Run();
es.execute(r);
es.execute(r);
es.shutdown();
}
结果:
public static void main(String[] args) {
ExecutorService es=Executors.newCachedThreadPool();
es.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
es.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
es.shutdown();
}
结果:
- shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
- shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
ThreadPoolExecutor:
另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
public ThreadPoolExecutor(int corePoolSize,//核心线程大小
int maximumPoolSize,//线程池最大线程数量
long keepAliveTime,//空闲线程存活时间
TimeUnit unit,//空闲线程存活时间单位
BlockingQueue<Runnable> workQueue,//工作队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler//拒绝策略) {
..................
}
参数说明:
corePoolSize,//核心线程大小
maximumPoolSize,//线程池最大线程数量
keepAliveTime,//空闲线程存活时间
unit,//空闲线程存活时间单位
workQueue,//工作队列
hreadFactory,//线程工厂
handler//拒绝策略(
AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作;
CallerRunsPolicy策略: 如果线程池的线程数量达到上限,该策略会把任务队列中的任务放在调用者线程当中运行;
DiscardOledestPolicy策略: 该策略会丢弃任务队列中最老的一个任务,也就是当前任务队列中最先被添加进去的,马上要被执行的那个任务,并尝试再次提交;
DiscardPolicy策略: 该策略会默默丢弃无法处理的任务,不予任何处理。当然使用此策略,业务场景中需允许任务的丢失;
也可以自己扩展RejectedExecutionHandler接口,定义自己的拒绝策略(了解)
)