Java基礎(一)

1.hashcode 與 equals:java

equals相等的必定相等,hashcode的則不必定。數組

2.hashtable和hashmap,concurrenthashtable,treemap緩存

hashtable是基於dictionary類的,而且每一個方法都加了syscnoized,因此是線程安全的,hashmap實現了map接口,而且是線程不安全的,concurrenthashmap是是線程安全的,裏面方法加了鎖處理。concurrenthashtable能夠看做是多個HashTable的組合,每一個「HashTable」單元成爲一個段,一個段的掉爲「HashTable」數組的航渡,模式是InitailCapacity/16,在ConcurrentHashTable中initialCapacity使用戶建立時傳入進去的,容量和大小是不同的,大小是指元素的總個數。hashmap裏面hashcode同樣時,經過keys.equals方法來找到對應的entry。hashtable採用synchronized關鍵字加鎖的原理,實際上是對對象加鎖,不論你是在方法前加synchronized仍是語句塊前加,鎖住的都是對象總體。可是concurrenthashmap採用的時lock。hashmap底層是數組加鏈表或者數組加紅黑樹,treemap採用的是紅黑樹。hashmap容許key和value都爲null,hashtable,treemap不能夠。安全

3.線程池服務器

  • corePoolSize: 線程池維護線程的最少數量
  • maximumPoolSize:線程池維護線程的最大數量
  • keepAliveTime: 線程池維護線程所容許的空閒時間
  • unit: 線程池維護線程所容許的空閒時間的單位
  • workQueue: 線程池所使用的緩衝隊列
  • handler: 線程池對拒絕任務的處理策略
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);
  • 線程池執行的過程:併發

  • 線程池剛建立時,裏面沒有一個線程。任務隊列是做爲參數傳進來的。不過,就算隊列裏面有任務,線程池也不會立刻執行它們。
  • 當調用 execute() 方法添加一個任務時,線程池會作以下判斷:
    ​ a. 若是正在運行的線程數量小於 corePoolSize,那麼立刻建立線程運行這個任務;
    ​ b. 若是正在運行的線程數量大於或等於 corePoolSize,那麼將這個任務放入隊列。
    ​ c. 若是這時候隊列滿了,並且正在運行的線程數量小於 maximumPoolSize,那麼仍是要建立線程運行這個任務;
    ​ d. 若是隊列滿了,並且正在運行的線程數量大於或等於 maximumPoolSize,那麼線程池會拋出異常,告訴調用者「我不能再接受任務了」。
  • 當一個線程完成任務時,它會從隊列中取下一個任務來執行。
  • 當一個線程無事可作,超過必定的時間(keepAliveTime)時,線程池會判斷,若是當前運行的線程數大於corePoolSize,那麼這個線程就被停掉。因此線程池的全部任務完成後,它最終會收縮到 corePoolSize 的大小。

  • corePoolSize:核心池的大小,這個參數跟後面講述的線程池的實現原理有很是大的關係。在建立了線程池後,默認狀況下,線程池中並無任何線程,而是等待有任務到來才建立線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就能夠看出,是預建立線程的意思,即在沒有任務到來以前就建立corePoolSize個線程或者一個線程。默認狀況下,在建立了線程池後,線程池中的線程數爲0,當有任務來以後,就會建立一個線程去執行任務,當線程池中的線程數目達到corePoolSize後,就會把到達的任務放到緩存隊列當中;
  • maximumPoolSize:線程池最大線程數,這個參數也是一個很是重要的參數,它表示在線程池中最多能建立多少個線程;
  • keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。默認狀況下,只有當線程池中的線程數大於corePoolSize時,keepAliveTime纔會起做用,直到線程池中的線程數不大於corePoolSize,即當線程池中的線程數大於corePoolSize時,若是一個線程空閒的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。可是若是調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大於corePoolSize時,keepAliveTime參數也會起做用,直到線程池中的線程數爲0;
  • TimeUnit.DAYS;               //天
    TimeUnit.HOURS;             //小時
    TimeUnit.MINUTES;           //分鐘
    TimeUnit.SECONDS;           //秒
    TimeUnit.MILLISECONDS;      //毫秒
    TimeUnit.MICROSECONDS;      //微妙
    TimeUnit.NANOSECONDS;       //納秒

    workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,通常來講,這裏的阻塞隊列有如下幾種選擇:異步

  • threadFactory:線程工廠,主要用來建立線程;
  • handler:表示當拒絕處理任務時的策略,有如下四種取值:
  • ArrayBlockingQueue和PriorityBlockingQueue使用較少,通常使用LinkedBlockingQueue和Synchronous。線程池的排隊策略與BlockingQueue有關。線程

  • 1)ArrayBlockingQueue:基於數組的先進先出隊列,此隊列建立時必須指定大小;rest

    2)LinkedBlockingQueue:基於鏈表的先進先出隊列,若是建立時沒有指定此隊列大小,則默認爲Integer.MAX_VALUE;code

    3)synchronousQueue:這個隊列比較特殊,它不會保存提交的任務,而是將直接新建一個線程來執行新來的任務。

  • ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。 
    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,可是不拋出異常。 
    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
    ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
    public abstract class AbstractExecutorService implements ExecutorService {
     
        protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { };
        protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { };
        public Future<?> submit(Runnable task) {};
        public <T> Future<T> submit(Runnable task, T result) { };
        public <T> Future<T> submit(Callable<T> task) { };
        private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                                boolean timed, long nanos)
            throws InterruptedException, ExecutionException, TimeoutException {
        };
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException {
        };
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                               long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        };
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException {
        };
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                             long timeout, TimeUnit unit)
            throws InterruptedException {
        };
    }
    public interface ExecutorService extends Executor {
     
        void shutdown();
        boolean isShutdown();
        boolean isTerminated();
        boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException;
        <T> Future<T> submit(Callable<T> task);
        <T> Future<T> submit(Runnable task, T result);
        Future<?> submit(Runnable task);
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException;
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                      long timeout, TimeUnit unit)
            throws InterruptedException;
     
        <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException;
        <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                        long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }
    public interface Executor {
        void execute(Runnable command);
    }

    在ThreadPoolExecutor類中有幾個很是重要的方法:

execute()方法其實是Executor中聲明的方法,在ThreadPoolExecutor進行了具體的實現,這個方法是ThreadPoolExecutor的核心方法,經過這個方法能夠向線程池提交一個任務,交由線程池去執行。

submit()方法是在ExecutorService中聲明的方法,在AbstractExecutorService就已經有了具體的實現,在ThreadPoolExecutor中並無對其進行重寫,這個方法也是用來向線程池提交任務的,可是它和execute()方法不一樣,它可以返回任務執行的結果,去看submit()方法的實現,會發現它實際上仍是調用的execute()方法,只不過它利用了Future來獲取任務執行結果(Future相關內容將在下一篇講述)。

shutdown()和shutdownNow()是用來關閉線程池的。

線程池狀態:

volatile int runState;
static final int RUNNING    = 0;
static final int SHUTDOWN   = 1;
static final int STOP       = 2;
static final int TERMINATED = 3;

當建立線程池後,初始時,線程池處於RUNNING狀態;

若是調用了shutdown()方法,則線程池處於SHUTDOWN狀態,此時線程池不可以接受新的任務,它會等待全部任務執行完畢;

若是調用了shutdownNow()方法,則線程池處於STOP狀態,此時線程池不能接受新的任務,而且會去嘗試終止正在執行的任務;

當線程池處於SHUTDOWN或STOP狀態,而且全部工做線程已經銷燬,任務緩存隊列已經清空或執行結束後,線程池被設置爲TERMINATED狀態。

ThreadPoolExecute

private final BlockingQueue<Runnable> workQueue;              //任務緩存隊列,用來存放等待執行的任務
private final ReentrantLock mainLock = new ReentrantLock();   //線程池的主要狀態鎖,對線程池狀態(好比線程池大小
                                                              //、runState等)的改變都要使用這個鎖
private final HashSet<Worker> workers = new HashSet<Worker>();  //用來存放工做集
 
private volatile long  keepAliveTime;    //線程存貨時間   
private volatile boolean allowCoreThreadTimeOut;   //是否容許爲核心線程設置存活時間
private volatile int   corePoolSize;     //核心池的大小(即線程池中的線程數目大於這個參數時,提交的任務會被放進任務緩存隊列)
private volatile int   maximumPoolSize;   //線程池最大能容忍的線程數
 
private volatile int   poolSize;       //線程池中當前的線程數
 
private volatile RejectedExecutionHandler handler; //任務拒絕策略
 
private volatile ThreadFactory threadFactory;   //線程工廠,用來建立線程
 
private int largestPoolSize;   //用來記錄線程池中曾經出現過的最大線程數
 
private long completedTaskCount;   //用來記錄已經執行完畢的任務個數

 

Executors 提供了一系列工廠方法用於創先線程池,返回的線程池都實現了 ExecutorService 接口。

// 建立固定數目線程的線程池。
public static ExecutorService newFixedThreadPool(int nThreads)

// 建立一個可緩存的線程池,調用execute將重用之前構造的線程(若是線程可用)。
// 若是現有線程沒有可用的,則建立一個新線 程並添加到池中。
// 終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。
public static ExecutorService newCachedThreadPool()

// 建立一個單線程化的Executor。
public static ExecutorService newSingleThreadExecutor()

// 建立一個支持定時及週期性的任務執行的線程池,多數狀況下可用來替代Timer類。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

這四種方法都是用的 Executors 中的 ThreadFactory 創建的線程。

newCachedThreadPool()

  • 緩存型池子,先查看池中有沒有之前創建的線程,若是有,就 reuse 若是沒有,就建一個新的線程加入池中
  • 緩存型池子一般用於執行一些生存期很短的異步型任務 所以在一些面向鏈接的 daemon 型 SERVER 中用得很少。但對於生存期短的異步任務,它是 Executor 的首選。
  • 能 reuse 的線程,必須是 timeout IDLE 內的池中線程,缺省 timeout 是 60s,超過這個 IDLE 時長,線程實例將被終止及移出池。

newFixedThreadPool(int)

  • newFixedThreadPool 與 cacheThreadPool 差很少,也是能 reuse 就用,但不能隨時建新的線程。
  • 其獨特之處:任意時間點,最多隻能有固定數目的活動線程存在,此時若是有新的線程要創建,只能放在另外的隊列中等待,直到當前的線程中某個線程終止直接被移出池子。
  • 和 cacheThreadPool 不一樣,FixedThreadPool 沒有 IDLE 機制(可能也有,但既然文檔沒提,確定很是長,相似依賴上層的 TCP 或 UDP IDLE 機制之類的),因此 FixedThreadPool 多數針對一些很穩定很固定的正規併發線程,多用於服務器。
  • 從方法的源代碼看,cache池和fixed 池調用的是同一個底層 池,只不過參數不一樣:
  • fixed 池線程數固定,而且是0秒IDLE(無IDLE)。
  • cache 池線程數支持 0-Integer.MAX_VALUE(顯然徹底沒考慮主機的資源承受能力),60 秒 IDLE 。

newScheduledThreadPool(int)

  • 調度型線程池
  • 這個池子裏的線程能夠按 schedule 依次 delay 執行,或週期執行

SingleThreadExecutor()

  • 單例線程,任意時間池中只能有一個線程
  • 用的是和 cache 池和 fixed 池相同的底層池,但線程數目是 1-1,0 秒 IDLE(無 IDLE)
相關文章
相關標籤/搜索