線程、線程池

什么叫線程

線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位谣光。它被包含在進(jìn)程之中檩淋,是進(jìn)程中的實(shí)際運(yùn)作單位。

進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)萄金,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位蟀悦,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)(百度百科)

創(chuàng)建線程的三種方式

一、繼承Thread類(lèi):

class MyThread extends Thread {
    public void run() {
        //這里是線程要執(zhí)行的任務(wù)
    }
}

Thread t = new MyThread();
t.start();

二氧敢、實(shí)現(xiàn)Runnable接口

class MyRunnable implements Runnable {
     ...
    public void run() {
         //這里是新線程需要執(zhí)行的任務(wù)
    }
}
 
Runnable r = new MyRunnable();
Thread t = new Thread(r);

三日戈、通過(guò)Callable和Future創(chuàng)建線程:

1、Callable與Runnable對(duì)比
public interface Runnable {
    public abstract void run();
}

由于run()方法返回值為void類(lèi)型孙乖,所以在執(zhí)行完任務(wù)之后無(wú)法返回任何結(jié)果浙炼。

Callable位于java.util.concurrent包下份氧,它也是一個(gè)接口,在它里面也只聲明了一個(gè)方法弯屈,只不過(guò)這個(gè)方法叫做call():

public interface Callable<V> {
    V call() throws Exception;
}

這是一個(gè)泛型接口蜗帜,call()函數(shù)返回的類(lèi)型就是傳遞進(jìn)來(lái)的V類(lèi)型。

2资厉、Future

Future就是對(duì)于具體的Runnable或者Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消厅缺、查詢是否完成、獲取結(jié)果酌住。必要時(shí)可以通過(guò)get方法獲取執(zhí)行結(jié)果店归,該方法會(huì)阻塞直到任務(wù)返回結(jié)果阎抒。

Future類(lèi)位于java.util.concurrent包下酪我,它是一個(gè)接口:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

在Future接口中聲明了5個(gè)方法,下面依次解釋每個(gè)方法的作用:

cancel 方法 用來(lái)取消任務(wù)且叁,如果取消任務(wù)成功則返回true都哭,如果取消任務(wù)失敗則返回false。參數(shù)mayInterruptIfRunning表示是否允許取消正在執(zhí)行卻沒(méi)有執(zhí)行完畢的任務(wù)逞带,如果設(shè)置true欺矫,則表示可以取消正在執(zhí)行過(guò)程中的任務(wù)。如果任務(wù)已經(jīng)完成展氓,則無(wú)論mayInterruptIfRunning為true還是false穆趴,此方法肯定返回false,即如果取消已經(jīng)完成的任務(wù)會(huì)返回false遇汞;如果任務(wù)正在執(zhí)行未妹,若mayInterruptIfRunning設(shè)置為true,則返回true空入,若mayInterruptIfRunning設(shè)置為false络它,則返回false;如果任務(wù)還沒(méi)有執(zhí)行歪赢,則無(wú)論mayInterruptIfRunning為true還是false化戳,肯定返回true。

isCancelled 方法表示任務(wù)是否被取消成功埋凯,如果在任務(wù)正常完成前被取消成功点楼,則返回 true。

isDone 方法表示任務(wù)是否已經(jīng)完成白对,若任務(wù)完成盟步,則返回true;

get() 方法用來(lái)獲取執(zhí)行結(jié)果躏结,這個(gè)方法會(huì)產(chǎn)生阻塞却盘,會(huì)一直等到任務(wù)執(zhí)行完畢才返回狰域;
get(long timeout, TimeUnit unit)用來(lái)獲取執(zhí)行結(jié)果,如果在指定時(shí)間內(nèi)黄橘,還沒(méi)獲取到結(jié)果兆览,就直接返回null。
也就是說(shuō)Future提供了三種功能:

1)判斷任務(wù)是否完成塞关;
2)能夠中斷任務(wù)抬探;
3)能夠獲取任務(wù)執(zhí)行結(jié)果。

因?yàn)镕uture只是一個(gè)接口帆赢,所以是無(wú)法直接用來(lái)創(chuàng)建對(duì)象使用的小压,因此就有了下面的FutureTask。

3椰于、FutureTask
public class FutureTask<V> implements RunnableFuture<V>

FutureTask類(lèi)實(shí)現(xiàn)了RunnableFuture接口怠益,我們看一下RunnableFuture接口的實(shí)現(xiàn):

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

可以看出RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實(shí)現(xiàn)了RunnableFuture接口瘾婿。所以它既可以作為Runnable被線程執(zhí)行蜻牢,又可以作為Future得到Callable的返回值。

FutureTask提供了2個(gè)構(gòu)造器:

public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}

事實(shí)上偏陪,F(xiàn)utureTask是Future接口的一個(gè)唯一實(shí)現(xiàn)類(lèi)抢呆。

具體使用

 public class MyCallable implements Callable<String>{

        @Override
        public String call() throws Exception {
            return "hello";
        }
    }


FutureTask futureTask = new FutureTask(new MyCallable());
futureTask.run();
   try {
            String str = (String) futureTask.get();
            Log.e("myMessage"," "+str);
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


1.使用Callable+Future獲取執(zhí)行結(jié)果

public class Test {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> result = executor.submit(task);
        executor.shutdown();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("主線程在執(zhí)行任務(wù)");
         
        try {
            System.out.println("task運(yùn)行結(jié)果"+result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("所有任務(wù)執(zhí)行完畢");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子線程在進(jìn)行計(jì)算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

2.使用Callable+FutureTask獲取執(zhí)行結(jié)果

public class Test {
    public static void main(String[] args) {
        //第一種方式
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();
         
        //第二種方式,注意這種方式和第一種方式效果是類(lèi)似的笛谦,只不過(guò)一個(gè)使用的是ExecutorService抱虐,一個(gè)使用的是Thread
        /*Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();*/
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("主線程在執(zhí)行任務(wù)");
         
        try {
            System.out.println("task運(yùn)行結(jié)果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("所有任務(wù)執(zhí)行完畢");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子線程在進(jìn)行計(jì)算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

線程的生命周期

871366-20160407193001656-5598813.jpg

線程共包括以下 5 種狀態(tài):

  1. 新建狀態(tài)(New): 線程對(duì)象被創(chuàng)建后,就進(jìn)入了新建狀態(tài)饥脑。例如恳邀,Thread thread = new Thread()。
  2. 就緒狀態(tài)(Runnable): 也被稱為“可執(zhí)行狀態(tài)”好啰。線程對(duì)象被創(chuàng)建后轩娶,其它線程調(diào)用了該對(duì)象的start()方法,從而來(lái)啟動(dòng)該線程框往。例如鳄抒,thread.start()。處于就緒狀態(tài)的線程椰弊,隨時(shí)可能被CPU調(diào)度執(zhí)行许溅。
  3. 運(yùn)行狀態(tài)(Running): 線程獲取CPU權(quán)限進(jìn)行執(zhí)行。需要注意的是秉版,線程只能從就緒狀態(tài)進(jìn)入到運(yùn)行狀態(tài)贤重。
  4. 阻塞狀態(tài)(Blocked): 阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行清焕。直到線程進(jìn)入就緒狀態(tài)并蝗,才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)祭犯。阻塞的情況分三種:
    (01) 等待阻塞 -- 通過(guò)調(diào)用線程的wait()方法,讓線程等待某工作的完成滚停。
    (02) 同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因?yàn)殒i被其它線程所占用)沃粗,它會(huì)進(jìn)入同步阻塞狀態(tài)。
    (03) 其他阻塞 -- 通過(guò)調(diào)用線程的sleep()或join()或發(fā)出了I/O請(qǐng)求時(shí)键畴,線程會(huì)進(jìn)入到阻塞狀態(tài)最盅。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)起惕、或者I/O處理完畢時(shí)涡贱,線程重新轉(zhuǎn)入就緒狀態(tài)。
  5. 死亡狀態(tài)(Dead): 線程執(zhí)行完了或者因異常退出了run()方法惹想,該線程結(jié)束生命周期问词。

Thread類(lèi)的常用方法除了我們之前提到的用于啟動(dòng)線程的start外還有:

(1)sleep方法

sleep 方法,這是一個(gè)靜態(tài)方法勺馆,作用是讓當(dāng)前線程進(jìn)入休眠狀態(tài)(但線程不會(huì)釋放已獲取的鎖)戏售,這個(gè)休眠狀態(tài)其實(shí)就是我們上面提到過(guò)的Time Waiting狀態(tài)侨核,從休眠狀態(tài)“蘇醒”后草穆,線程會(huì)進(jìn)入到Runnable狀態(tài)。sleep方法有兩個(gè)重載版本搓译,聲明分別如下:

public static native void sleep(long millis) throws InterruptedException; //讓當(dāng)前線程休眠millis指定的毫秒數(shù)
public static native void sleep(long millis, int nanos) throws InterruptedException; //在毫秒數(shù)的基礎(chǔ)上還指定了納秒數(shù)悲柱,控制粒度更加精細(xì)

(2)join 方法

join 方法,這是一個(gè)實(shí)例方法些己,在當(dāng)前線程中對(duì)一個(gè)線程對(duì)象調(diào)用join方法會(huì)導(dǎo)致當(dāng)前線程停止運(yùn)行豌鸡,等那個(gè)線程運(yùn)行完畢后再接著運(yùn)行當(dāng)前線程。也就是說(shuō)段标,把當(dāng)前線程還沒(méi)執(zhí)行的部分“接到”另一個(gè)線程后面去涯冠,另一個(gè)線程運(yùn)行完畢后,當(dāng)前線程再接著運(yùn)行逼庞。join方法有以下重載版本:

public final synchronized void join() throws InterruptedException 
public final synchronized void join(long millis) throws InterruptedException; 
public final synchronized void join(long millis, int nanos) throws InterruptedException;

無(wú)參數(shù)的join表示當(dāng)前線程一直等到另一個(gè)線程運(yùn)行完畢蛇更,這種情況下當(dāng)前線程會(huì)處于Wating狀態(tài);帶參數(shù)的表示當(dāng)前線程只等待指定的時(shí)間赛糟,這種情況下當(dāng)前線程會(huì)處于Time Waiting狀態(tài)派任。當(dāng)前線程通過(guò)調(diào)用join方法進(jìn)入Time Waiting或Waiting狀態(tài)后,會(huì)釋放已經(jīng)獲取的鎖璧南。實(shí)際上掌逛,join方法內(nèi)部調(diào)用了Object類(lèi)的實(shí)例方法wait,關(guān)于這個(gè)方法我們下面會(huì)具體介紹司倚。

(3)yield 方法

yield 方法豆混,這是一個(gè)靜態(tài)方法篓像,作用是讓當(dāng)前線程“讓步”,目的是為了讓優(yōu)先級(jí)不低于當(dāng)前線程的線程有機(jī)會(huì)運(yùn)行皿伺,這個(gè)方法不會(huì)釋放鎖遗淳。

(4)interrupt 方法

interrupt 方法,這是一個(gè)實(shí)例方法心傀。每個(gè)線程都有一個(gè)中斷狀態(tài)標(biāo)識(shí)屈暗,這個(gè)方法的作用就是將相應(yīng)線程的中斷狀態(tài)標(biāo)記為true,這樣相應(yīng)的線程調(diào)用isInterrupted方法就會(huì)返回true脂男。通過(guò)使用這個(gè)方法养叛,能夠終止那些通過(guò)調(diào)用可中斷方法進(jìn)入阻塞狀態(tài)的線程。常見(jiàn)的可中斷方法有sleep宰翅、wait弃甥、join,這些方法的內(nèi)部實(shí)現(xiàn)會(huì)時(shí)不時(shí)的檢查當(dāng)前線程的中斷狀態(tài)汁讼,若為true會(huì)立刻拋出一個(gè)InterruptedException異常淆攻,從而終止當(dāng)前線程。

(5)wait方法

wait方法是Object類(lèi)中定義的實(shí)例方法嘿架。在指定對(duì)象上調(diào)用wait方法能夠讓當(dāng)前線程進(jìn)入阻塞狀態(tài)(前提是當(dāng)前線程持有該對(duì)象的內(nèi)部鎖(monitor))瓶珊,此時(shí)當(dāng)前線程會(huì)釋放已經(jīng)獲取的那個(gè)對(duì)象的內(nèi)部鎖,這樣一來(lái)其他線程就可以獲取這個(gè)對(duì)象的內(nèi)部鎖了耸彪。當(dāng)其他線程獲取了這個(gè)對(duì)象的內(nèi)部鎖伞芹,進(jìn)行了一些操作后可以調(diào)用notify方法來(lái)喚醒正在等待該對(duì)象的線程。

(6)notify/notifyAll方法

notify/notifyAll方法也是Object類(lèi)中定義的實(shí)例方法蝉娜。它倆的作用是喚醒正在等待相應(yīng)對(duì)象的線程唱较,區(qū)別在于前者喚醒一個(gè)等待該對(duì)象的線程,而后者喚醒所有等待該對(duì)象的線程召川。這么說(shuō)比較抽象南缓,下面我們來(lái)舉一個(gè)具體的例子來(lái)說(shuō)明以下wait和notify/notifyAll的用法。請(qǐng)看以下代碼

public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
      
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == 0){
                        try {
                            System.out.println("隊(duì)列空荧呐,等待數(shù)據(jù)");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();          //每次移走隊(duì)首元素
                    queue.notify();
                    System.out.println("從隊(duì)列取走一個(gè)元素汉形,隊(duì)列剩余"+queue.size()+"個(gè)元素");
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("隊(duì)列滿,等待有空余空間");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(1);        //每次插入一個(gè)元素
                    queue.notify();
                    System.out.println("向隊(duì)列取中插入一個(gè)元素坛增,隊(duì)列剩余空間:"+(queueSize-queue.size()));
                }
            }
        }
    }
}

以上代碼描述的是經(jīng)典的“生產(chǎn)者-消費(fèi)者”問(wèn)題获雕。Consumer類(lèi)代表消費(fèi)者,Producer類(lèi)代表生產(chǎn)者收捣。在生產(chǎn)者進(jìn)行生產(chǎn)之前届案,會(huì)獲取queue的內(nèi)部鎖(monitor)。然后判斷隊(duì)列是否已滿罢艾,若滿了則無(wú)法再生產(chǎn)楣颠,所以調(diào)用queue.wait方法尽纽,從而等待在queue對(duì)象上。(釋放了queue的內(nèi)部鎖)此時(shí)消費(fèi)者能夠能夠獲取queue的monitor從而進(jìn)入consume方法童漩,這樣一來(lái)它就會(huì)通過(guò)queue.poll方法進(jìn)行消費(fèi)弄贿,于是隊(duì)列不再滿了,接著它調(diào)用queue.notify方法來(lái)通知正在等待的生產(chǎn)者矫膨,生產(chǎn)者就會(huì)從剛才阻塞的wait方法中返回差凹。同理,當(dāng)隊(duì)列空時(shí)侧馅,消費(fèi)者也會(huì)等待 生產(chǎn)者來(lái)喚醒危尿。

線程池

一.Java中的ThreadPoolExecutor類(lèi)

java.uitl.concurrent.ThreadPoolExecutor類(lèi)是線程池中最核心的一個(gè)類(lèi),因此如果要透徹地了解Java中的線程池馁痴,必須先了解這個(gè)類(lèi)谊娇。下面我們來(lái)看一下ThreadPoolExecutor類(lèi)的具體實(shí)現(xiàn)源碼。

在ThreadPoolExecutor類(lèi)中提供了四個(gè)構(gòu)造方法:

public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
    ...
}

從上面的代碼可以得知罗晕,ThreadPoolExecutor繼承了AbstractExecutorService類(lèi)济欢,并提供了四個(gè)構(gòu)造器,事實(shí)上小渊,通過(guò)觀察每個(gè)構(gòu)造器的源碼具體實(shí)現(xiàn)法褥,發(fā)現(xiàn)前面三個(gè)構(gòu)造器都是調(diào)用的第四個(gè)構(gòu)造器進(jìn)行的初始化工作。

下面解釋下一下構(gòu)造器中各個(gè)參數(shù)的含義:

corePoolSize:核心池的大小粤铭,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系挖胃。在創(chuàng)建了線程池后杂靶,默認(rèn)情況下梆惯,線程池中并沒(méi)有任何線程,而是等待有任務(wù)到來(lái)才創(chuàng)建線程去執(zhí)行任務(wù)吗垮,除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法垛吗,從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思烁登,即在沒(méi)有任務(wù)到來(lái)之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程怯屉。默認(rèn)情況下,在創(chuàng)建了線程池后饵沧,線程池中的線程數(shù)為0锨络,當(dāng)有任務(wù)來(lái)之后,就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù)狼牺,當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后羡儿,就會(huì)把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中;

maximumPoolSize:線程池最大線程數(shù)是钥,這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù)掠归,它表示在線程池中最多能創(chuàng)建多少個(gè)線程缅叠;

keepAliveTime:表示線程沒(méi)有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。默認(rèn)情況下虏冻,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)肤粱,keepAliveTime才會(huì)起作用,直到線程池中的線程數(shù)不大于corePoolSize厨相,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)领曼,如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止蛮穿,直到線程池中的線程數(shù)不超過(guò)corePoolSize悯森。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí)绪撵,keepAliveTime參數(shù)也會(huì)起作用瓢姻,直到線程池中的線程數(shù)為0;

unit:參數(shù)keepAliveTime的時(shí)間單位音诈,有7種取值幻碱,在TimeUnit類(lèi)中有7種靜態(tài)屬性:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小時(shí)
TimeUnit.MINUTES;           //分鐘
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //納秒

workQueue:一個(gè)阻塞隊(duì)列,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù)细溅,這個(gè)參數(shù)的選擇也很重要褥傍,會(huì)對(duì)線程池的運(yùn)行過(guò)程產(chǎn)生重大影響,一般來(lái)說(shuō)喇聊,這里的阻塞隊(duì)列有以下幾種選擇:

ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;

ArrayBlockingQueue和PriorityBlockingQueue使用較少恍风,一般使用LinkedBlockingQueue和Synchronous。線程池的排隊(duì)策略與BlockingQueue有關(guān)誓篱。

threadFactory:線程工廠朋贬,主要用來(lái)創(chuàng)建線程;

handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略窜骄,有以下四種取值:

ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常锦募。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常邻遏。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù)糠亩,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過(guò)程)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

常用的線程池

FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

如上,F(xiàn)ixedThreadPool中核心線程數(shù)等于線程池可容納的最大線程數(shù)准验,這意味著FixedThreadPool中只存在核心線程赎线,并且核心線程處于空閑狀態(tài)也不會(huì)被終止。這表示FixedThreadPool線程池能快速地響應(yīng)外界的任務(wù)請(qǐng)求糊饱。
當(dāng)所有核心線程都處于活動(dòng)狀態(tài)時(shí)垂寥,后續(xù)提交的任務(wù)就會(huì)進(jìn)入LinkedBlockingQueue隊(duì)列中,此隊(duì)列默認(rèn)的容量是Integer.MAX_VALUE,即可理解為無(wú)限制矫废。

CacheThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

如上盏缤,CacheThreadPool線程池不存在核心線程,但是它可容納的非核心線程數(shù)可看作是無(wú)限制的蓖扑,又因?yàn)镾ynchronousQueue隊(duì)列通常是無(wú)法存儲(chǔ)元素的唉铜,這就表示,當(dāng)提交了一個(gè)線程任務(wù)時(shí)律杠,因?yàn)闆](méi)有核心線程存在潭流,并且也無(wú)法插入到SynchronousQueue隊(duì)列中排隊(duì)等外,所以就會(huì)使用一個(gè)非核心線程來(lái)執(zhí)行這個(gè)任務(wù)柜去。因?yàn)樵O(shè)置了60s的空閑時(shí)長(zhǎng)灰嫉,所以被用來(lái)執(zhí)行任務(wù)的非核心線程會(huì)先考慮處于空閑狀態(tài)的非核心線程,如果沒(méi)有空閑的線程嗓奢,就會(huì)創(chuàng)建新線程來(lái)執(zhí)行任務(wù)讼撒。當(dāng)任務(wù)都執(zhí)行完成后,并且超過(guò)了空閑時(shí)長(zhǎng)股耽,那么線程就會(huì)被回收根盒,當(dāng)沒(méi)有提交任務(wù),并且所有空閑線程都被回收后物蝙,CacheThreadPool是不會(huì)占用系統(tǒng)資源的炎滞。從CacheThreadPool的特性來(lái)看,可以用它來(lái)執(zhí)行大量的耗時(shí)較少的任務(wù)诬乞。

SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

如上册赛,SingleThreadExecutor線程池中只存在一個(gè)核心線程,并且任務(wù)隊(duì)LinkedBlockingQueue的容量是無(wú)限制的震嫉。這意味著使用該線程池執(zhí)行線程任務(wù)森瘪,同一時(shí)間只有一個(gè)線程任務(wù)在執(zhí)行,在執(zhí)行中的任務(wù)沒(méi)有完成之前责掏,后續(xù)到來(lái)的線程任務(wù)都會(huì)進(jìn)入LinkedBlockingQueue隊(duì)列中排隊(duì)等待柜砾。SingleThreadExecutor線程池使用同一個(gè)線程按任務(wù)提交順序執(zhí)行多個(gè)線程任務(wù),使得這些任務(wù)之間不需要處理線程同步的問(wèn)題换衬。

ScheduledThreadPool

//Executors.java
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

ScheduledThreadPoolExecutor.java

private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

ScheduledThreadPool線程池主要用于執(zhí)行延時(shí)任務(wù),或重復(fù)執(zhí)行某個(gè)任務(wù)证芭。線程任務(wù)通過(guò)
ScheduledExecutorService類(lèi)的 schedule|scheduleAtFixedRate|scheduleWithFixedDelay
方法提交到線程池中瞳浦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市废士,隨后出現(xiàn)的幾起案子叫潦,更是在濱河造成了極大的恐慌,老刑警劉巖官硝,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矗蕊,死亡現(xiàn)場(chǎng)離奇詭異短蜕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)傻咖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)朋魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人卿操,你說(shuō)我怎么就攤上這事警检。” “怎么了害淤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扇雕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我窥摄,道長(zhǎng)镶奉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任崭放,我火速辦了婚禮腮鞍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘莹菱。我一直安慰自己移国,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布道伟。 她就那樣靜靜地躺著迹缀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜜徽。 梳的紋絲不亂的頭發(fā)上祝懂,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音拘鞋,去河邊找鬼砚蓬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盆色,可吹牛的內(nèi)容都是我干的灰蛙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隔躲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼摩梧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起宣旱,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仅父,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體笙纤,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耗溜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了省容。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抖拴。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蓉冈,靈堂內(nèi)的尸體忽然破棺而出城舞,到底是詐尸還是另有隱情,我是刑警寧澤寞酿,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布家夺,位于F島的核電站,受9級(jí)特大地震影響伐弹,放射性物質(zhì)發(fā)生泄漏拉馋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一惨好、第九天 我趴在偏房一處隱蔽的房頂上張望煌茴。 院中可真熱鬧,春花似錦日川、人聲如沸蔓腐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)回论。三九已至任柜,卻和暖如春猿推,著一層夾襖步出監(jiān)牢的瞬間赐俗,已是汗流浹背秧秉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脊串,地道東北人窜醉。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓拌汇,卻偏偏與公主長(zhǎng)得像缚甩,于是被迫代替她去往敵國(guó)和親谱净。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一蹄胰、引言 我們都知道線程和線程池是Android開(kāi)發(fā)中很重要的一個(gè)部分岳遥。本文會(huì)從Java線程談起,由淺及深總結(jié)在A...
    Yink_Liu閱讀 859評(píng)論 0 3
  • 為加深對(duì)線程的理解捻艳,首先推薦一篇文章:我是一個(gè)線程 線程 進(jìn)程就是在某種程度上相互隔離、獨(dú)立運(yùn)行的程序庆猫。和進(jìn)程一樣...
    itcode閱讀 1,393評(píng)論 0 12
  • 線程 進(jìn)程就是在某種程度上相互隔離、獨(dú)立運(yùn)行的程序杉畜。和進(jìn)程一樣纪蜒,線程在程序中是獨(dú)立的、并發(fā)的執(zhí)行路徑此叠,每個(gè)線程有它...
    那年的歌閱讀 1,272評(píng)論 0 0
  • 一.線程與進(jìn)程相關(guān) 1.進(jìn)程 ??定義:進(jìn)程是具有獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)纯续,進(jìn)程是操作系統(tǒng)分...
    Geeks_Liu閱讀 1,713評(píng)論 2 4
  • 包子茸歧,生日快樂(lè)倦炒! 一年前的五月,一只柯基來(lái)到了我的家软瞎,取名包子逢唤,因?yàn)榭鞓?lè)愛(ài)吃包子,所以取了個(gè)狗不理的名字铜涉。 還記得...
    Lilys_0987閱讀 945評(píng)論 0 11