Thread & ThreadPoolExecutor

Thread.State

  • NEW

Thread state for a thread which has not yet started.
这里就是我们平时New完一个线程后的初始状态。

  • RUNNABLE

Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor
调用了start()方法后线程进入运行状态。

  • BLOCKED

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling
线程尝试获取锁(synchronized)失败后,进入等待阻塞状态。

  • WAITING

Thread state for a waiting thread. Thread in the waiting state is waiting for another thread to perform a particular action.
线程获取锁后,调用wait()后,此时已经释放锁,需要获取锁的其他线程调用notify重新竞争锁。

  • TIMED_WAITING

Thread in the waiting state is waiting for another thread to perform a particular action.
调用wait(Time) 后等待一定时间,时间到后自动唤醒重新获得锁

  • TERMINATED

Thread state for a terminated thread. The thread has completed execution.
线程终止,已经执行完毕。

Thread中断

在线程运行(run)中间打断,Java中提供了3种方法:

//中断线程(实例方法) 
public void Thread.interrupt(); 

//判断线程是否被中断(实例方法) 
public boolean Thread.isInterrupted(); 

//判断是否被中断并清除当前中断状态(静态方法) 
public static boolean Thread.interrupted();

当一个线程处于被阻塞状态或者试图执行一个阻塞操作时,使用Thread.interrupt()方式中断该线程,此时将会抛出异常,同时中断状态将会被复位(由中断状态改为非中断状态),如我们创建一个线程,并在线程中调用了sleep方法从而使用线程进入阻塞状态,启动线程后,调用线程实例对象的interrupt方法后线程会进入阻塞异常,并抛出InterruptedException异常,此时中断状态也将被复位。

除了阻塞中断的情景,我们还可能会遇到处于运行期且非阻塞的状态的线程,这种情况下,Thread.interrupt()是不会得到任响应的,非阻塞状态下的线程需要我们手动进行中断检测并结束程序,例如:

    ......
    while(true){ //判断当前线程是否被中断 
        if (this.isInterrupted()){ 
            System.out.println("线程中断"); 
            break; 
        } 
    }
    ......

综合所述,可以简单总结一下中断两种情况,一种是当线程处于阻塞状态或者试图执行一个阻塞操作时,我们可以使用实例方法interrupt()进行线程中断,执行中断操作后将会抛出interruptException异常(该异常必须捕捉无法向外抛出)并将中断状态复位,另外一种是当线程处于运行状态时,我们也可调用实例方法interrupt()进行线程中断,但同时必须手动判断中断状态,并编写中断线程的代码(其实就是结束run方法体的代码)。

中断与synchronized

线程的中断操作对于正在等待获取的锁对象的synchronized方法或者代码块并不起作用,也就是对于synchronized来说,如果一个线程在等待锁,那么结果只有两种,要么它获得这把锁继续执行,要么它就保存等待,即使调用中断线程的方法,也不会生效,不过此时isInterrupted()为true。

等待唤醒机制与synchronized

等待唤醒机制本篇主要指的是notify/notifyAll和wait方法,在使用这3个方法时,必须处于synchronized代码块或者synchronized方法中,否则就会抛出IllegalMonitorStateException异常,这是因为调用这几个方法前必须拿到当前对象的监视器monitor对象,也就是说notify/notifyAll和wait方法依赖于monitor对象(synchronized关键字可以获取monitor)
需要特别理解的一点是,与sleep方法不同的是wait方法调用完成后,线程将被暂停,但wait方法将会释放当前持有的监视器锁(monitor),直到有线程调用notify/notifyAll方法后方能继续执行,而sleep方法只让线程休眠并不释放锁。同时notify/notifyAll方法调用后,并不会马上释放监视器锁,而是在相应的synchronized(){}/synchronized方法执行结束后才自动释放锁。

ThreadPoolExecutor

diagrams.png
  • corePoolSize : 线程池中的线程数量,包括空闲线程

Core pool size is the minimum number of workers to keep alive (and not allow to time out etc) unless allowCoreThreadTimeOut is set, in which case the minimum is zero.

  • maxmumPoolSize : 池中允许的最大线程数

Maximum pool size. Note that the actual maximum is internally bounded by CAPACITY.

  • keepAliveTime : 线程数大于核心数时,空闲线程等待任务的有效时间,用于空闲线程过多时回收线程的参数

Timeout in nanoseconds for idle threads waiting for work. Threads use this timeout when there are more than corePoolSize present or if allowCoreThreadTimeOut. Otherwise they wait forever for new work.

  • workQueue:存储任务的队列,当前线程数量在coreSize和maxSize之间时,会先将任务放入队列中等待执行,若队列已满,会创建线程(不超过最大线程数)

The queue used for holding tasks and handing off to worker threads. We do not require that workQueue.poll() returning null necessarily means that workQueue.isEmpty(), so rely solely on isEmpty to see if the queue is empty (which we must do for example when deciding whether to transition from SHUTDOWN to TIDYING). This accommodates special-purpose queues such as DelayQueues for which poll() is allowed to return null even if it may later return non-null when delays expire.

  • threadFactory:创建线程的工厂类

Factory for new threads. All threads are created using this factory (via method addWorker).

  • handler:线程池和等待队列已满时执行的拒绝策略

Handler called when saturated or shutdown in execute.

  • 线程池的运行思路

When a new task is submitted in method {@link #execute(Runnable)}, and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full. By setting corePoolSize and maximumPoolSize the same, you create a fixed-size thread pool. By setting maximumPoolSize to an essentially unbounded value such as {@code Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically using {@link #setCorePoolSize} and {@link #setMaximumPoolSize}.
当前线程数量小于corePoolSize时,会直接新建线程执行新提交的Runnable。
当前线程数量大于corePoolSize且等待队列未满,新提交的Runnable会加入等待队列中。
当前线程数量大于corePoolSize小于maximumPoolSize,且等待队列已满,会直接新建线程执行新提交的Runnable。

New tasks submitted in method {@link #execute(Runnable)} will be em>rejected</em> when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated.
当前线程数量大于maximumPoolSize,且等待队列已满,会采取拒绝策略。
In the default {@link ThreadPoolExecutor.AbortPolicy}, the handler throws a runtime {@link RejectedExecutionException} upon rejection.
默认策略AbortPolicy,会抛出一个运行时异常。
In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread that invokes {@code execute} itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
CallerRunsPolicy策略,调用线程自己直接run task。
In {@link ThreadPoolExecutor.DiscardPolicy}, a task that cannot be executed is simply dropped.
DiscardPolicy策略,直接抛弃Runnable不会有异常。
In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)
DiscardOldestPolicy策略,丢弃队列中头部的任务,再次尝试提交任务,如果再次失败则重复此策略。

If the pool currently has more than corePoolSize threads,excess threads will be terminated if they have been idle for more than the keepAliveTime
如果线程池的当前数量大于corePoolSize,额外的线程闲置时间超过 keepAliveTime 会自动停止。
In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread that invokes {@code execute} itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容