線(xiàn)程
現(xiàn)在操作系統(tǒng)在運(yùn)行程序時(shí),會(huì)為其創(chuàng)建一個(gè)進(jìn)程?,F(xiàn)代操作系統(tǒng)調(diào)度最小單元是線(xiàn)程。一個(gè)進(jìn)程里可以有多個(gè)線(xiàn)程。這些線(xiàn)程有自己獨(dú)立的計(jì)數(shù)器堆棧局部變量等屬性,并且能訪(fǎng)問(wèn)共享的內(nèi)存變量。處理器來(lái)回在這些線(xiàn)程上切換,使用者感覺(jué)這些線(xiàn)程在同時(shí)執(zhí)行。
Java天生就是多線(xiàn)程程序。main()方法是一個(gè)名為main的線(xiàn)程在運(yùn)行。
為什么多線(xiàn)程
1、更多的處理器核心,使用多線(xiàn)程將計(jì)算邏輯分配到多個(gè)處理器核心,更有效率
2、更快的響應(yīng)時(shí)間。多線(xiàn)程同時(shí)處理復(fù)雜計(jì)算,盡快完成邏輯,提升用戶(hù)體驗(yàn)
3、更好的編程模型。Java為多線(xiàn)程編程提供了良好、考究并且一致的編程模型,使開(kāi)發(fā)人員能夠更加專(zhuān)注于問(wèn)題的解決,即為所遇到的問(wèn)題建立合適的模型,而不是絞盡腦汁地考慮如何將其多線(xiàn)程化。一旦開(kāi)發(fā)人員建立好了模型,稍做修改總是能夠方便地映射到Java提供的多線(xiàn)程編程模型上。
線(xiàn)程的狀態(tài)
線(xiàn)程在運(yùn)行的生命周期可能會(huì)有以下幾種狀態(tài)。在同一時(shí)刻只能處于其中一種狀態(tài)

Daemon線(xiàn)程
Daemon線(xiàn)程是一種支持型線(xiàn)程。主要用作程序中后臺(tái)調(diào)度以及支持性工作。如果JVM中不存在非Daemon線(xiàn)程,JVM可能會(huì)退出。可以通過(guò)Thread.setDaemon(true)將線(xiàn)程設(shè)置為Daemon線(xiàn)程。
啟動(dòng)終止線(xiàn)程
運(yùn)行線(xiàn)程之前要先構(gòu)造一個(gè)線(xiàn)程對(duì)象。一個(gè)新構(gòu)造的線(xiàn)程對(duì)象是由其parent線(xiàn)程來(lái)進(jìn)行空間分配的。child線(xiàn)程繼承了parent是否為Daemon、優(yōu)先級(jí)、加載資源的contextClassLoader以及可繼承的ThreadLocal。同時(shí)還會(huì)分配一個(gè)唯一的id來(lái)標(biāo)識(shí)這個(gè)child線(xiàn)程。此時(shí)線(xiàn)程狀態(tài)為初始狀態(tài),在堆內(nèi)存中等待運(yùn)行。
啟動(dòng)線(xiàn)程
線(xiàn)程對(duì)象初始化完成以后,可以調(diào)用start()方法啟動(dòng)這個(gè)線(xiàn)程。線(xiàn)程start方法的含義是,當(dāng)前線(xiàn)程同步告知JVM,只要線(xiàn)程規(guī)劃器空閑,應(yīng)該立即啟動(dòng)調(diào)用start方法。
注意:?jiǎn)?dòng)一個(gè)線(xiàn)程之前,最好為這個(gè)線(xiàn)程設(shè)置名稱(chēng)。
理解中斷
中斷可以理解為一個(gè)線(xiàn)程的標(biāo)識(shí)位屬性,他表示一個(gè)運(yùn)行中的線(xiàn)程是否被其他線(xiàn)程進(jìn)行了中斷操作。中斷好比其他線(xiàn)程對(duì)這個(gè)線(xiàn)程打了個(gè)招呼,其他線(xiàn)程調(diào)用該線(xiàn)程的interrupt方法對(duì)其進(jìn)行了中斷操作。
線(xiàn)程通過(guò)檢查自身是否被中斷來(lái)相應(yīng),線(xiàn)程通過(guò)方法isInterrupted()來(lái)進(jìn)行判斷是否被中斷,也可以調(diào)用靜態(tài)方法Thread.interrupted()對(duì)當(dāng)前線(xiàn)程的中斷標(biāo)識(shí)位進(jìn)行復(fù)位。如果該線(xiàn)程已處于終結(jié)狀態(tài),或者已經(jīng)被中斷過(guò),在調(diào)用該線(xiàn)程對(duì)象的isInterrupted依舊會(huì)返回false。
安全的終止線(xiàn)程
除了中斷以外,可以通過(guò)一個(gè)boolean變量來(lái)控制是否需要停止任務(wù)終止線(xiàn)程。
線(xiàn)程間通信
線(xiàn)程開(kāi)始運(yùn)行,擁有自己的棧空間,按照代碼運(yùn)行,直到結(jié)束。
volatile和synchronized關(guān)鍵字
Java多線(xiàn)程在同時(shí)訪(fǎng)問(wèn)一個(gè)對(duì)象或者對(duì)象的成員變量,每個(gè)線(xiàn)程都有這個(gè)變量的拷貝。在程序執(zhí)行過(guò)程中,一個(gè)線(xiàn)程看到的變量不一定是最新的。
volatile可以修飾字段,告知程序任何對(duì)變量的訪(fǎng)問(wèn)需要從共享內(nèi)存中獲取,對(duì)它的改變必須同步刷新回共享內(nèi)存,能保證所有線(xiàn)程對(duì)變量訪(fǎng)問(wèn)的可見(jiàn)性。
synchronized關(guān)鍵字修飾方法或者同步塊,確保多個(gè)線(xiàn)程在同一個(gè)時(shí)刻,只有一個(gè)線(xiàn)程處于方法或者同步塊中,保證了線(xiàn)程對(duì)變量訪(fǎng)問(wèn)的可見(jiàn)性和排他性。synchronized本質(zhì)是對(duì)一個(gè)monitor進(jìn)行獲取,這個(gè)獲取過(guò)程是排他的。只能有一個(gè)線(xiàn)程獲取到,同一時(shí)刻。
任意一個(gè)對(duì)象都擁有自己的監(jiān)視器。當(dāng)這個(gè)對(duì)象由同步塊或者這個(gè)對(duì)象的同步方法調(diào)用時(shí),執(zhí)行方法的線(xiàn)程必須先獲取到該對(duì)象的監(jiān)視器才能進(jìn)入同步塊或者同步方法,沒(méi)有獲取到監(jiān)視器的線(xiàn)程會(huì)阻塞在同步塊和同步方法的入口處,進(jìn)入blocked狀態(tài)。
等待通知機(jī)制

線(xiàn)程A調(diào)用了對(duì)象o的wait()方法進(jìn)入等待狀態(tài),另一個(gè)線(xiàn)程B調(diào)用了O的notify()或者notifyAll()方法,線(xiàn)程A收到通知后從對(duì)象O的wait方法返回,進(jìn)而進(jìn)行后續(xù)操作。2個(gè)線(xiàn)程通過(guò)對(duì)象O來(lái)完成交互。對(duì)象上的wait和notify方法就像開(kāi)關(guān)信號(hào)一樣,用來(lái)完成等待方和通知方之間的交互工作
ThreadLocal的使用
threadlocal對(duì)象是以threadlocal對(duì)象為鍵,任意對(duì)象為值得存儲(chǔ)結(jié)構(gòu)。一個(gè)線(xiàn)程可以根據(jù)一個(gè)threadlocal對(duì)象查詢(xún)到綁定在這個(gè)線(xiàn)程上的一個(gè)值。
可以通過(guò)set方法設(shè)置一個(gè)值,在當(dāng)前線(xiàn)程在通過(guò)get方法獲取到原先設(shè)置的值。