一.线程池的概念与引入
1.线程池的引入
首先介绍在tcp服务器变成模型的原理,每一个客户端连接用一个单独的线程为之服务,当与客户端的会话结束时,线程也就结束了,即每来一个客户端连接,服务器端就要创建一个新线程。这好比假设每个报名学员都要通过我来亲自接待,以便给每个学员一种好的感觉,但每个学员报名手续要花费半小时,对于50名同学,我一个个接待何为之办理手续,显然不实际,我会怎么做呢?我会闲接待每一个学员,打完招呼后,再把他分配给一名工作人员去办理手续,这样,我就接待了每名学员
如果访问服务器的客户端很多,那么服务器要不断地创建和销毁线程,这将严重影响服务器的性能.如果真的来一名学员,我们都安排一名新工作人员为之服务,也是不可能的,那公司岂不是要招聘很多工作人员?而是应该一名工作人员服务完一名学员,空闲下来后,一旦有新的学员要服务,我又立即安排该工作人员为新学员服务。线程池的概念与此类似,首先创建一些线程,它们的集合称为线程池,当服务器接受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中
在线程池的变成模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,这就是封装。记住,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务
线程池的概念与Executors类的应用
做服务器的话,就会用到线程池这个知识
2.创建固定大小的线程池
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);//固定的线程池
for(int i = 1 ;i<=10;i++) {
final int task = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int j = 1; j < 10; j++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task);
}
}
});
}
System.out.println("all of 10 tasks have committed! ");
}
}
- 因为只有3个线程,所以一直只有3个线程运作
3.创建缓存线程池
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();//缓存的线程池 当任务来了,服务不过来了,自动增加线程,它里面对应线程是不定的 线程数量是动态变化的
for(int i = 1 ;i<=10;i++) {
final int task = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int j = 1; j < 10; j++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task);
}
}
});
}
System.out.println("all of 10 tasks have committed! ");
}
}
4.创建单一线程池(如果实现线程死掉后重新启动)
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();//单线程 如果池子里的线程死了,它会立马产生一个新的线程,反正就是一直保持一个线程的存在
for(int i = 1 ;i<=10;i++) {
final int task = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int j = 1; j < 10; j++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task);
}
}
});
}
System.out.println("all of 10 tasks have committed! ");
}
}
二.关闭线程池
- shutdown与shutdownNow的比较
- shutdown();//池子里面没有任何任务了,就关闭了
- shutdownNow();立即关闭
三.用线程池启动定时器
1.隔几秒炸
Executors.newScheduledThreadPool(3).schedule(new Runnable() {
@Override
public void run() {
System.out.println("bombing");
}
},
10,
TimeUnit.SECONDS);
2.隔几秒炸,之后几秒循环炸
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() {//固定频率
@Override
public void run() {
System.out.println("bombing");
}
},
6,
2,
TimeUnit.SECONDS);
调用ScheduledExecutorService的schedule方法,返回ScheduleFuture对象可以取消任务
支持间隔重复任务的定时方式,不直接支持绝对定时方式,需要转换成相对时间方式
比如如果你想定在今晚凌晨3点,但是没有这种方法,直接指定Date方法
- 凌晨三点的时间-此刻的时间
Date.getTime()-System.currentTimeMillis()