Java執行緒相關知識,執行緒池底層源碼分享和相關面試題(持續更新)
執行緒
執行緒有哪些狀態
*/ NEW, //當執行緒對象對創建後,即進入了新建狀態,如:Thread t = new MyThread() /** * 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. */ RUNNABLE, //當調用執行緒對象的start()方法,執行緒即進入就緒狀態。處於就緒狀態的執行緒,只是說明此執行緒已經做好了準備,隨時等待CPU調度執行,並不是說執行了start()此執行緒立即就會執行 /** * 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 * {@link Object#wait() Object.wait}. */ BLOCKED, //處於運行狀態中的執行緒由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才有機會再次被CPU調用以進入到運行狀態,
/** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, //這個狀態下是不能分配CPU執行的,可使用Object.wait(),Thread,join(),LockSupport.park進入這個狀態 /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING,//其實這個狀態和Waiting就是有沒有超時時間的差別,這個狀態下也是不能分配CPU執行的 /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; //在我們的執行緒正常run結束之後或者run一半異常了就是終止狀態
終止執行緒的方式
1.Tread.stop(). 2.Tread.interrupt()
推薦使用interrupt,因為使用stop之後,這個執行緒帶有的鎖也會消失,因此不推薦使用這個方法,interrupt()會使得執行緒Waiting和Timed_Waiting狀態的執行緒拋出 interruptedException異常,調用interrupt()方法後,使得Running狀態的執行緒再調用wait()、sleep()、jion()方法時拋出interruptedException異常,需要在catch中處理執行緒異常後的問題。
進程和執行緒的區別
來源於一個知乎老哥 //www.zhihu.com/question/25532384 比較容易理解
做個簡單的比喻:進程=火車,執行緒=車廂
執行緒在進程下行進(單純的車廂無法運行)
一個進程可以包含多個執行緒(一輛火車可以有多個車廂)
不同進程間數據很難共享(一輛火車上的乘客很難換到另外一輛火車,比如站點換乘)
同一進程下不同執行緒間數據很易共享(A車廂換到B車廂很容易)
進程要比執行緒消耗更多的電腦資源(採用多列火車相比多個車廂更耗資源)
進程間不會相互影響,一個執行緒掛掉將導致整個進程掛掉(一列火車不會影響到另外一列火車,但是如果一列火車上中間的一節車廂著火了,將影響到所有車廂)
進程使用的記憶體地址可以上鎖,即一個執行緒使用某些共享記憶體時,其他執行緒必須等它結束,才能使用這一塊記憶體。(比如火車上的洗手間)-”互斥鎖”
進程使用的記憶體地址可以限定使用量(比如火車上的餐廳,最多只允許多少人進入,如果滿了需要在門口等,等有人出來了才能進去)-「訊號量」
sleep方法和wait方法區別
都可以使當前執行緒放棄CPU一定的時間從而暫停,但是如果有鎖的話,sleep方法不會釋放這個鎖,wait方法會, sleep方法必須要設定時間,wait方法可設定可不設定。 sleep屬於Thread類,wait方法屬於Object類
wait,notify方法存在的問題(Condition 下的await和signal也是一樣)
notify和wait必須在synchrnizied同步塊中執行,並且成對出現,只有先wait再notify才能被喚醒,否則無法喚醒。
1.繼承Thread類,重寫run方法
2.實現Runnable介面,重寫run方法
3.實現Callable介面,重寫call方法
4.使用執行緒池
ThreadLocal原理
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
進程之間的通訊方式有哪些
管道pipe:管道是一種半雙工的通訊方式,數據只能單向流動,而且只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。
命名管道FIFO:有名管道也是半雙工的通訊方式,但是它允許無親緣關係進程間的通訊。
消息隊列MessageQueue:消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了訊號傳遞資訊少、管道只能承載無格式位元組流以及緩衝區大小受限等缺點。
共享存儲SharedMemory:共享記憶體就是映射一段能被其他進程所訪問的記憶體,這段共享記憶體由一個進程創建,但多個進程都可以訪問。共享記憶體是最快的 IPC 方式,它是針對其他進程間通訊方式運行效率低而專門設計的。它往往與其他通訊機制,如訊號量,配合使用,來實現進程間的同步和通訊。
訊號量Semaphore:訊號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同執行緒之間的同步手段。
套接字Socket:套解口也是一種進程間通訊機制,與其他通訊機制不同的是,它可用於不同及其間的進程通訊。
執行緒池
執行緒池各個參數講解
public ThreadPoolExecutor(int corePoolSize, //執行緒池核心工作執行緒數量,比如newFixedThreadPool中可以自定義的執行緒數量就是這個參數 int maximumPoolSize, //執行緒池所有工作執行緒的數量,比如newFixedThreadPool中的最大工作執行緒就是核心執行緒數,newCachedThreadPool中的最大工作執行緒數是Integer.MAX_VALUE long keepAliveTime, //非核心執行緒存活的時間,當核心執行緒不夠用的時候,創建出來的輔助工作執行緒在完成任務空閑多久後會被回收 TimeUnit unit, //上面一個參數的單位,分。秒等 BlockingQueue<Runnable> workQueue,//底層使用的阻塞隊列數據結構,比如newFixedThreadPool底層使用LinkedBlockingQueue。工作隊列,保存已提交但是未執行的任務 ThreadFactory threadFactory, //創建工作執行緒的工廠,保持默認即可 RejectedExecutionHandler handler) { //拒絕策略,即在所有工作執行緒數達到上限,底層阻塞隊列也滿了的時候採取的策略 if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
常用執行緒池
日常使用中使用哪種執行緒池
上面四種都不使用,我們需要通過ThreadPoolExcutor自定義執行緒池,阿里巴巴java開發手冊明確指出,不允許使用Excutors工具類進行執行緒池的創建,因為某些開發人員不了解底層運行規則,避免資源耗盡的危險
1:FixedThreadPool 和 SingleThreadPool: 允許的請求隊列(底層實現是LinkedBlockingQueue)長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM
2:CachedThreadPool 和 ScheduledThreadPool 允許的創建執行緒數量為Integer.MAX_VALUE,可能會創建大量的執行緒,從而導致OOM
執行緒池4種拒絕策略
new ThreadPoolExecutor.AbortPolicy(); //遇到執行緒池達到最大執行緒數,且隊列已經滿了,直接拋異常 —-默認
new ThreadPoolExecutor.DiscardOldestPolicy() //遇到執行緒池達到最大執行緒數且隊列已經滿了,則丟棄隊列中最前面的任務,
new ThreadPoolExecutor.DiscardPolicy() //遇到執行緒池達到最大執行緒數且隊列已經滿了,丟棄當前任務,不給它加入隊列中
new ThreadPoolExecutor.CallerRunsPolicy();//會將任務返回給提交者進行執行,比如讓main執行緒直接執行run方法
執行緒池優點
1.避免大量執行緒的創建銷毀帶來的性能開銷
2.避免大量執行緒之間因為相互搶佔系統資源導致的阻塞狀態
3.能夠對執行緒進行簡單的管理並提供定時執行,間隔執行等功能
在IO密集型和CPU密集型下執行緒池最大執行緒數選擇
在CPU密集型下,選用cpu核心數+1作為最大執行緒池工作執行緒數量,減少cpu切換任務帶來的開銷
在IO密集型下,儘可能多的加大工作執行緒數量,一般為cpu核心數*2
執行緒池提交任務時excute和submit有什麼區別
1.兩者接收參數不一致,excute接收Runnable介面,submit接收Callable介面
2.submit有返回值,execute沒有返回值
3.submit支援返回Future
執行緒池狀態
private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
RUNNING:執行緒池的初始狀態,可以添加待執行的任務
SHUTDOWN:執行緒池處於待關閉狀態,不接受新任務,但會處理完已接收的任務
STOP:執行緒池立即關閉,不接收新的任務,放棄快取隊列中的任務並且中斷正在處理的任務
TIDYING:執行緒池自主整理狀態,調用 terminated() 方法進行執行緒池整理
TERMINATED:執行緒池終止狀態