1.创建线程池的四种方式:
第一种:
//--corePoolSize:核心线程数。
//--当线程池初次创建时,是没有任何线程的。当有请求发起时,线程会创建核心线程
//--在请求过程中,无论核心线程是否闲置,线程池都会创建核心线程,直到满足数量位置
//--maximumPoolSize:最大线程数=核心线程数+临时线程数
//--keepAliveTime:临时线程的存活时间
//--unit:时间单位,一般用毫秒单位
//--workQueue:等待队列,用于存放还未处理的请求
ExecutorService service=
new ThreadPoolExecutor(5,
10,
3000,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("请稍后尝试");
}
});
//--通过线程池启动线程
for(int i=0;i<21;i++){
service.execute(new ClientRunner());
}
//--关闭线程池。此方法调用时,线程池不会接受外部请求了。
//--但内部的线程并不会马上销毁,而是等到线程工作完之后再销毁
//--使用线程池的好处可以避免线程的频繁创建和销毁,节省cpu性能。
service.shutdown();
第二种:
/*newCachedThreadPool:
*①没有核心线程
*②都是临时线程
*③队列是同步队列
*④最大线程数 Integer.MaxValue
*总结:大池子小队列的好处:
*可以很好的响应(及时)客户端请求。因为不需要等待排队。
*但是注意:这种线程池适用短请求。如果都是长请求,可能会导致线程一直创建而不销毁,最后内存溢出
*/
public void testCreate_1(){
ExecutorService service=Executors.newCachedThreadPool();
}
第三种:
/*newFixedThreadPool:
*①都是核心线程,没有临时线程
*②队列是无界队列(LinkedBlockingQueue)
*总结:小池子大队列
*这种线程池的作用:消峰限流。局限性是:不能及时响应客户端请求
*/
public void testCreate_2(){
ExecutorService service=Executors.newFixedThreadPool(10);
}
第四:
newSingleThreadExecutor
Executors.newSingleThreadExecutor()返回一个线程池(这个线程池只有一个线程),
这个线程
池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去
!
2.线程生命周期(状态)
2.1.
新建状态(
NEW
)
当程序
使用 new 关键字创建了一个线程之后
,该线程就处于新建状态,此时仅由 JVM 为其分配
内存,并初始化其成员变量的值
13/04/2018
Page 59 of 283
2.2.
就绪状态(
RUNNABLE
):
当线程对象
调用了 start()方法之后
,该线程处于就绪状态。Java 虚拟机会为其创建方法调用栈和
程序计数器,等待调度运行。
2.3.
运行状态(
RUNNING
):
如果处于
就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体
,则该线程处于运行状
态。
2.4.
阻塞状态(
BLOCKED
):
阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时停止运行。
直到线程进入可运行(runnable)状态,才有机会再次获得 cpu timeslice 转到运行(running)状
态。阻塞的情况分三种:
等待阻塞(
o.wait->
等待对列):
运行(running)的线程执行 o.wait()方法,JVM 会把该线程放入等待队列(waitting queue)
中。
同步阻塞
(lock->
锁池
)
运行(running)的线程在获取对象的同步锁时,若该
同步锁被别的线程占用
,则 JVM 会把该线
程放入锁池(lock pool)中。
其他阻塞
(sleep/join)
运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,
JVM 会把该线程置为阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O
处理完毕时,线程重新转入可运行(runnable)状态。
2.5.
线程死亡(
DEAD
)
线程会以下面三种方式结束,结束后就是死亡状态。
正常结束
1. run()或 call()方法执行完成,线程正常结束。
异常结束
2. 线程抛出一个未捕获的 Exception 或 Error。
调用
stop
3. 直接调用该线程的 stop()方法来结束该线程—
该方法通常容易导致死锁
,不推荐使用。