Java线程池的使用以及原理

时间:2023-03-10 02:57:56
Java线程池的使用以及原理

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543909.html 

一:线程池简介

在使用多线程来提高处理器利用率的同时,由于线程的不断创建和销毁所造成的时间浪费变得明显。假如使用线程的时间代价为:T1创建线程、T2线程执行、T3销毁线程。使用线程这个时间我们不能优化,但是T1、T3这两个时间我们可以进行优化。线程池就是基于这样的思路:随着线程池的创建,在线程池中先创建并维护一定数量的线程,这些线程是空闲的。然后在我们需要线程来处理工作时,从线程池中调用一条空闲的线程来使用;用完之后在把线程“释放”回线程池;如果同时有多于可以线程数量的任务请求,则扩充线程池,直到最大容量;如果线程池最大容量仍不够数量,则把请求加入任务队列中阻塞,等待有执行完任务回到线程池的线程。

二:线程池使用

在concurrent包中提供了5种线程池,各有各特性,可以按需取用:

Java线程池的使用以及原理

上面五种线程池的使用方式大同小异:

1:创建线程池,在构造函数中指明线程池初始化大小(即创建多少条工作线程)

2:通过线程池对象的excute(Runnable r)方法执行任务线程:在任务线程中定义你要做的工作,然后把这个任务线程对象作为excute()方法的参数传递进线程池。线程池管理器会自动从线程池中取一条空闲的线程来运行这个任务线程,执行工作。

如:

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
}
}
    package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
    package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
    package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}

三:线程池原理

一个线程池包括以下四个基本组成部分:
                1、线程池类:用于创建并管理线程池,包括 创建线程池,销毁线程池,管理并分配工作线程;
                2、工作线程:线程池中线程,在没有任务时处于等待状态,被分配任务时执行任务,执行完后回到线程池,可以循环使用;
                3、任务队列:用于存放没有处理的任务,一般基于阻塞队列来实现。

excute(runnable)的原理:参数是一个runnable对象(可以继承Thread类来实现,也可以实现Runnable接口来创建),在重写的run()方法里说明了工作任务,通过excute(runnable)方法传进线程池申请工作线程来执行它;如果线程池中有空闲线程,则分配,执行该runnable对象;如果没有空闲线程可用,则把该runnable添加到任务队列中;线程池会不断轮询任务队列,在有空闲线程并且任务队列非空的情况下,就会从任务队列取出任务线程来执行。

如果线程池已达到最大容量并且工作线程全部处于工作状态,任务队列也满了,则会拒绝后续的任务请求。

线程池的关闭:

  • shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  • shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务