标题java四种线程池及使用示例
1、线程工厂
1、我们先来写ThreadFactory,在创建线程池时候可以传入自定义的线程工厂,线程工厂说白了就是用来定制线程的一些属性:名字、优先级、是否为守护线程。直接看代码即可。
当然创建线程池的时候可以不传入自定义线程工厂。
public class MyThreadFactory implements ThreadFactory {
private static final String thread_prefix = "self_thread";
private AtomicInteger integer = new AtomicInteger(0);
private String threadName = null;
public MyThreadFactory(String threadName) {
this.threadName = threadName;
}
public MyThreadFactory() {
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
String name = threadName == null ? thread_prefix + " " + integer.getAndIncrement() : threadName + " " + integer.getAndIncrement();
thread.setName(name);
return thread;
}
}
2、我们来详细看一下四种线程池
单一线程的线程池 | 可缓存的线程池 | 可周期性执行的线程池 | 固定数目的线程池 |
---|---|---|---|
.newSingleThreadExecutor | .newCachedThreadPool | .newScheduledThreadPool | .newFixedThreadPool |
1、单一线程的线程池:
此线程池只有一个线程,用仅有的一个线程来执行任务,保证所有的任务按照指定顺序(FIFO,LIFO,优先级)执行,所有的任务都保存在队列LinkedBlockingQueue中,等待唯一的单线程来执行任务。
private static final Object lock = new Object();
private static int count = 0;
private static void testSingleThreadThreadPool() {
ExecutorService service = Executors.newSingleThreadExecutor(new MyThreadFactory("singleThread"));
for (int i = 0; i < 6; i++) {
test(service);
}
}
private static void test(ExecutorService service) {
synchronized (lock) {
count++;
System.out.println(Thread.currentThread().getName());
if (count == 5) {
System.out.println("count == 5 shutdown ");
service.shutdown();
}
}
}
可以从输出看到,只new了一个线程。
2、可缓存的线程池
创建一个可缓存的无界线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收,则新建线程。当线程池中的线程空闲时间超过60s,则会自动回收该线程,当任务超过线程池的线程数则创建新的线程,线程池的大小上限为Integer.MAX_VALUE,可看作无限大。
private static void testCachedThreadPool() {
ExecutorService service = Executors.newCachedThreadPool(new MyThreadFactory("cached"));
for (int i = 0; i < 1000; i++) { // 循环数稍微大一点 模拟线程回收后被复用
service.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()); // 可从控制台看出相同线程名的线程
}
});
}
}
3、可周期性执行的线程池
private static void testScheduleThreadPool() {
/**
* 可周期性执行的线程池 延迟2秒执行 每间隔4秒执行一次
*
* 是“以固定的频率”执行,period(周期)指的是两次成功执行之间的时间。
* 上一个任务开始的时间计时,一个period后,检测上一个任务是否执行完毕,
* 如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,
* 则需要等上一个任务执行完毕后立即执行。
*/
ExecutorService service = Executors.newScheduledThreadPool(6, new MyThreadFactory());
((ScheduledExecutorService) service).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
test(service);
}
}, 2, 4, TimeUnit.SECONDS);
// 定时 执行一次 的任务,延迟1s后执行
((ScheduledExecutorService) service).schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ", delay 1s");
}
}, 1, TimeUnit.SECONDS);
/**
* “以固定的延时”执行,delay(延时)指的是一次执行终止和下一次执行开始之间的延迟。
*/
((ScheduledExecutorService) service).scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
long start = new Date().getTime();
System.out.println("scheduleWithFixedDelay 开始执行时间:" +
DateFormat.getTimeInstance().format(new Date()));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = new Date().getTime();
System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m");
System.out.println("scheduleWithFixedDelay执行完成时间:"
+ DateFormat.getTimeInstance().format(new Date()));
System.out.println();
System.out.println();
}
}, 2, 3, TimeUnit.SECONDS);
}
4、固定数目的线程池
这个就很好理解了。固定数量的线程。
/**
* 固定数量的线程池
*/
private static void testFixedThreadPool() {
ExecutorService service = Executors.newFixedThreadPool(5, new MyThreadFactory());
for (int i = 0; i < 8; i++) {
service.submit(new Runnable() {
@Override
public void run() {
test(service);
}
});
}
}