SingleThreadPool
SingleThreadPool 的构造函数如下
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
newSingleThreadExecutor() 这是一个单线程池,至始至终都由一个线程来执行。它是FxiedThreadPool的极端方式。 作用:该方法返回一个只有一个线程的线程池,即每次只能执行一个线程任务,多余的任务会保存到一个任务 。FixedThreadPool和newSingleThreadExecutor:都有的问题申请解决队列可能会消耗十分大的内存,甚至OOM。
singleThreadExecutor的意义
Java中的singleThreadExecutor表示单线程池,就是这个线程池里面只有一个线程,这个对象存在的意义是什么?跟直接起一个线程有什么区别?
我的理解是不是单线程池的好处就是线程可以复用,将单线程池singleThreadExecutor声明成一个静态变量,完后在不同的A类,B类,C类中都可以在singleThreadExecutor的execute方法中去启动线程
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
}
}
这里虽然每次都用了new Runnable关键字,但这几个线程其实都是同一个线程?是这样理解吗?
首先要弄情况一个Runnable并非是一个线程,一个Thread才是一个线程。 singleThreadExecutor内部会创建一个Thread,这个Thread的工作就是从一个队列中取出用户提交的任务进行执行,如果执行过程中发生未受检的异常,singleThreadExecutor会自动重新启动一个线程再继续工作,这一点比用户自己创建一个线程自己管理轻松多了。同时自己维护一个任务队列也不是件简单的事,所以singleThreadExecutor的意义还是很大的。
一个线程的创建方式,可以自己通过直接new Thread的方式创建并启动。也可能通过new ThreadPool的方式间接创建。具体采用哪种,跟实际应用场景有关。 如对于满足以下场景可以直接用new Thread的方式。而不需要采用ThreadPool 1、线程执行任务内容已确定 2、线程不需要频繁创建和销毁 3、线程不需要重用(跟第2点有点类似) 场景举例:某项目中,需要提供一个定时记录用户在线数量的功能,记录操作异步独立进行。抽象代码如下:
public class Test {
public static int userNum = 10;
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
System.out.println("记录用户数:" + userNum);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//do other something.....
}
}
该线程会一直存在,异步独立运行着。这个场景下功能比较简单,是没必要采用singleThreadExecutor的。singleThreadExecutor是通过创建一个线程池来管理。内部做了大量处理,如自定义很多处理类、建立容器接收任务、处理任务时的加锁解锁操作、线程的状态判断等等。采用后者相关于做了很多没必要的工作。且内存占用也比前者多。 现在在换一种场景:某项目中,需要提供当有用户登录或下线时记录用户在线数量的功能。记录操作异步独立进行。上述代码可以调整为:
public class Test {
public static int userNum = 10;
public static void main(String[] args) {
//do other something.....
login();
//do other something.....
logout();
}
private static void logout() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("记录用户数:" + userNum);
}
}).start();
}
private static void login() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("记录用户数:" + userNum);
}
}).start();
}
}
这种场景下,你会发现该实现操作会出现大量线程的频繁创建的销毁。所以我们肯定要做一些优化。如优化成下面这种:
public class Test {
public static int userNum = 10;
static RecordThread th;
static {
th = new RecordThread();
th.start();
System.out.println("记录线程已启动");
}
public static void main(String[] args) {
System.out.println("do something.....");
login();
System.out.println("do something.....");
logout();
}
private static void logout() {
th.addTask(new Runnable() {
@Override
public void run() {
System.out.println("记录用户数:" + userNum);
}
});
}
private static void login() {
th.addTask(new Runnable() {
@Override
public void run() {
System.out.println("记录用户数:" + userNum);
}
});
}
}
class RecordThread extends Thread {
List<Runnable> taskList = new ArrayList<>();
@Override
public void run() {
while (true) {
if (taskList.size() > 0) {
Runnable task = taskList.remove(0);
task.run();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void addTask(Runnable task) {
taskList.add(task);
}
}
优化后我们又会发现新的问题:线程并发安全问题没处理(ArrayList)、任务执行异常将导致线程终止,如下代码:
private static void logout() {
th.addTask(new Runnable() {
@Override
public void run() {
throw new NullPointerException();
}
});
}
所以后续代码你会继续优化。最终随着你的优化,你会发现,最终代码相当于是你自己写了一个类似ThreadPool的管理类。 所以二者如何使用。楼主需要先了解二者的所拥有的功能。再实际场景中再去做选择。
综上所述,在全局需要要一个thread 的时候,就需要SingleThreadPool
SingleThreadPool 和 FixThreadPool(1) 有啥区别
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
FinalizableDelegatedExecutorService 这个类不可以造型成 ThreadPool进行coresize的修改了。所以和FixThreadPool 最大的区别就是SingleThreadExecutor 不可以修改CoreSize。