为什么使用线程池
- 为了降低资源的消耗,通过重复利用已创建的线程来降低创建和销毁线程造成的资源消耗。
- 提高响应的速度。当任务到达时,任务可以不需要等到线程创建就立即执行。
- 提高线程的可管理性。线程是比较稀缺的资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以统一的调度和分配,调优和监控,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。阿里禁止使用jdk自带的线程池,因为jdk的线程池是有缺陷的。
Executors类
JDK自带的四种线程池是通过Executors提供的
newCachedThreadPool
:创建一个可缓存线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,若无可回收,创建新线程。newFixedThreadPool
:创建一个定长的线程池,可以控制线程最大并发数,超出的线程会在队列中等待。newScheduledThreadPool
:创建一个定长的线程池,支持定时及周期性任务执行newSingleThreadExecutor
:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有的任务按照指定顺序执行
这四种线程池的初始化都调用了同一个构造器
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数的意义
corePoolSize
:线程池里线程的数量,核心线程池大小maximumPoolSize
:指定了线程池里的最大线程数量keepAliveTime
:当线程池线程数量大于corePoolSize
,多出来的空闲线程,多长时间被销毁unit
:时间单位workQueue
:任务队列,用于存放提交但是尚未被执行的任务threadFactory
:线程工厂,用来创建线程,线程工厂就是我们new
线程的handler
:拒绝策略,是将任务添加到线程池中时,线程池拒绝该任务多采取的相应的措施
常见的工作队列
ArrayBlockingQueue
:基于数组的有界阻塞队列。FIFO。LinkedBlockingQueue
:基于链表的有界阻塞队列。FIFO。
线程池提供了四种拒绝策略
AbortPolicy
:直接抛出异常,默认的策略。CallerRunPolicy
:用调用者所在的线程来执行任务DiscardOldestPolicy
:丢弃阻塞队列中最靠前的任务,并执行当前任务DiscardPolicy
:直接丢弃任务
public class Ch01 {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
Runnable taskOne = () -> {
System.out.println(Thread.currentThread().getName() + "taskOne...");
};
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
ExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 40; i++) {
fixedThreadPool.submit(taskOne);
}
}
}
自定义线程池
public class Ch02 {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
Ch02(String name){
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = name + "-" + poolNumber.getAndIncrement() + "-thread-";
}
Ch02(){
this("default");
}
public Thread newThread(Runnable r){
// 就是在创建线程
Thread t = new Thread(group,r,namePrefix + threadNumber.getAndIncrement(),0);
if(t.isDaemon()){
t.setDaemon(false);
}
if(t.getPriority() != Thread.NORM_PRIORITY){
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
public static void main(String[] args) {
Ch02 ch02 = new Ch02();
ch02.newThread(()->{
System.out.println("自定义线程池创建的线程...");
}).start();
}
}
两个线程轮流打印数字,从1-100
public class Test01 {
private static class MyNumberTest {
private static boolean flag = true;
// 要打印的数字
private static int count = 0;
public synchronized void print1() {
for (int i = 0; i < 50; i++) {
while (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "->" + ++count);
flag = !flag;
notifyAll();
}
}
public synchronized void print2() {
for (int i = 0; i < 50; i++) {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "->" + ++count);
flag = !flag;
notifyAll();
}
}
}
public static void main(String[] args) {
MyNumberTest myNumberTest = new MyNumberTest();
Thread t1 = new Thread(() -> {
myNumberTest.print1();
});
t1.setName("线程A");
Thread t2 = new Thread(() -> {
myNumberTest.print2();
});
t2.setName("线程B");
t1.start();
t2.start();
}
}
轮流打印数组内容
class Two extends Thread{
int [] arr1 = new int[]{1,2,3,4,5};
int [] arr2 = new int[]{-1,-2,-3,-4,-5};
private static boolean flag = true;
public synchronized void print1() {
for (int i = 0; i < arr1.length; i++) {
while (!flag) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(arr1[i]);
flag = !flag;
notifyAll();
}
}
public synchronized void print2() {
for (int i = 0; i < arr2.length; i++) {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(arr2[i]);
flag = !flag;
notifyAll();
}
}
}
public class Test03 {
public static void main(String[] args) {
Two two = new Two();
Thread t1 = new Thread(()->{
two.print1();
});
Thread t2 = new Thread(()->{
two.print2();
});
t1.start();
t2.start();
}
}
尽量不要理会那些使你认为你不成功的疑虑,勇往直前,即使最后失败也要做做看,其结果往往并非真的会失败。 ——比尔·盖茨