多線程

進(jìn)程:

是任務(wù)的執(zhí)行過(guò)程,持有資源(共享內(nèi)存和共享文件)和線程

資源:

是進(jìn)程和線程的載體


線程:

是系統(tǒng)中最小的執(zhí)行單元

同一進(jìn)程擁有多個(gè)線程

多個(gè)線程共享進(jìn)程的資源


此圖畫的關(guān)系有些問(wèn)題,因?yàn)閠hread也實(shí)現(xiàn)了Runnable接口


共享變量:

注:必須將共享變量變量聲明為volatile

使用volatile變量降低了發(fā)生內(nèi)存一致性錯(cuò)誤的風(fēng)險(xiǎn), 因?yàn)槿魏螌?duì)volatile變量的寫操作都與對(duì)該變量的讀操作建立了happens-before關(guān)系。這種關(guān)系意味著對(duì)volatile變量值的改變對(duì)其他線程總是可見(jiàn)的。更近一步, 當(dāng)一個(gè)線程讀取volatile變量的時(shí)候,該線程不但讀取了最近的變化,而且是導(dǎo)致該變化發(fā)生代碼的全部影響

如何正確停止線程?

@Java線程——如何正確停止線程

一、錯(cuò)誤一:stop()方法

1、not stop:stop()方法會(huì)使線程戛然而止

2、使程序突然中止,無(wú)法完成完整的業(yè)務(wù)步驟,也無(wú)法進(jìn)行清理工作

二、錯(cuò)誤二:interrupt()方法

1、interrupt()方法只能設(shè)置interrupt標(biāo)志位(且在線程阻塞情況下,標(biāo)志位會(huì)被清除,更無(wú)法設(shè)置中斷標(biāo)志位),無(wú)法停止線程

三、正確方法:設(shè)置退出標(biāo)志

1、使用退出標(biāo)志位來(lái)停止while循環(huán)

2、完成最后一次業(yè)務(wù)后跳出while循環(huán)后,之后進(jìn)行一些清理

interrupt()方法不會(huì)中斷一個(gè)正在運(yùn)行的線程。這一方法實(shí)際上完成的是,在線程受到阻塞時(shí)拋出一個(gè)中斷信號(hào),這樣線程就得以退出阻塞的狀態(tài)。更確切的說(shuō),如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那么,它將接收到一個(gè)中斷異常(InterruptedException),從而提早地終結(jié)被阻塞狀態(tài),然后該線程還是繼續(xù)運(yùn)行的

線程常用方法

1.獲取線程名稱:getName();

2.取得當(dāng)前線程對(duì)象:currentThread();

3.判斷是否啟動(dòng):isAlive();

4.強(qiáng)行運(yùn)行:join();

5.線程休眠:sleep();

6.線程禮讓:yield();

什么時(shí)候使用thread 什么時(shí)候使用runnable

其實(shí)兩種方式效果一樣,但推薦使用runnable

因?yàn)镴ava是單繼承,繼承了thread就不能繼承其他的類

而實(shí)現(xiàn)runnable接口的話,擴(kuò)展性要好很多

@Java線程——線程交互——爭(zhēng)用條件

1、當(dāng)多個(gè)線程同時(shí)共享訪問(wèn)同一數(shù)據(jù)(內(nèi)存區(qū)域)時(shí),每個(gè)線程都嘗試操作該數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)被破壞(corrupted),這種現(xiàn)象稱為爭(zhēng)用條件

2、原因是,每個(gè)線程在操作數(shù)據(jù)時(shí),會(huì)先將數(shù)據(jù)初值讀【取到自己獲得的內(nèi)存中】,然后在內(nèi)存中進(jìn)行運(yùn)算后,重新賦值到數(shù)據(jù)。

3、爭(zhēng)用條件:線程1在還【未重新將值賦回去時(shí)】,線程1阻塞,線程2開(kāi)始訪問(wèn)該數(shù)據(jù),然后進(jìn)行了修改,之后被阻塞的線程1再獲得資源,而將之前計(jì)算的值覆蓋掉線程2所修改的值,就出現(xiàn)了數(shù)據(jù)丟失情況

線程的交互:互斥與同步

互斥:在同一時(shí)間只能有一條線程對(duì)關(guān)鍵數(shù)據(jù)或臨界區(qū)進(jìn)行操作

同步:線程之間的一種通信機(jī)制

一條線程做了一件事情,然后用某種方式去告訴其它線程:"我做完了"

synchronized關(guān)鍵字實(shí)現(xiàn)互斥行為,既可以出現(xiàn)在方法體之上也可以出現(xiàn)在方法體內(nèi),以一種塊的形式出現(xiàn)。

然后通過(guò)lockObject的wait方法(注意:wait的線程被存放在wait set 中)和notifyAll方法實(shí)現(xiàn)同步。

步驟:

1.互斥:同一時(shí)間,只能有一個(gè)線程訪問(wèn)數(shù)據(jù)

2.同步:通信機(jī)制;一個(gè)線程完成,以某種方式通知其他線程

3.鎖的概念:private final Object lockObj = new Object();

4.互斥實(shí)現(xiàn)方式:synchronized關(guān)鍵字

synchronized(lockObj){---執(zhí)行代碼----}加鎖操作

lockObj.wait();線程等待狀態(tài),以避免線程持續(xù)申請(qǐng)鎖,不去競(jìng)爭(zhēng)cpu資源

lockObj.notifyAll();喚醒所有l(wèi)ockObj對(duì)象上等待的線程

同步是兩個(gè)線程之間的一種交互的操作(一個(gè)線程發(fā)出消息另外一個(gè)線程響應(yīng))。

同步的實(shí)現(xiàn):wait();notify();notifyAll();這三個(gè)方法都是屬于Java中的Object對(duì)象的成員函數(shù)。

調(diào)用wait();和notifyAll();方法使線程進(jìn)入等待或者喚醒不是在同一個(gè)線程的同一次操作中執(zhí)行的,當(dāng)操作結(jié)束,喚醒了所有的等待線程之后,線程又將有著公平的機(jī)會(huì)競(jìng)爭(zhēng)CPU資源。

注意:notify();方法喚醒wait set 中的一條線程使其具有競(jìng)爭(zhēng)CPU的機(jī)會(huì),具體喚醒那一條線程是隨機(jī)的由Java的底層算法決定,我們不能去控制。

通過(guò)synchronized關(guān)鍵字為臨界區(qū)(critical)加鎖,這樣在線程競(jìng)爭(zhēng)資源時(shí),當(dāng)某一條線程獲得鎖進(jìn)入臨界區(qū)后,其他線程將無(wú)法再次獲取鎖進(jìn)入臨界區(qū)(critical),直到獲得鎖的線程退出臨界區(qū)(critical),釋放鎖資源。Java的語(yǔ)法保證了同一時(shí)間只能有一條線程可以獲得lockObject。

java

1.原子性:Java內(nèi)存模型只保證了基本讀取和賦值是原子性操作,如果要實(shí)現(xiàn)更大范圍操作的原子性,可以通過(guò)synchronized和Lock來(lái)實(shí)現(xiàn)。由于synchronized和Lock能夠保證任一時(shí)刻只有一個(gè)線程執(zhí)行該代碼塊,那么自然就不存在原子性問(wèn)題了,從而保證了原子性。

2.可見(jiàn)性:對(duì)于可見(jiàn)性,Java提供了volatile關(guān)鍵字來(lái)保證可見(jiàn)性。當(dāng)一個(gè)共享變量被volatile修飾時(shí),它會(huì)保證修改的值會(huì)立即被更新到主存,當(dāng)有其他線程需要讀取時(shí),它會(huì)去內(nèi)存中讀取新值。而普通的共享變量不能保證可見(jiàn)性,因?yàn)槠胀ü蚕碜兞勘恍薷闹螅裁磿r(shí)候被寫入主存是不確定的,當(dāng)其他線程去讀取時(shí),此時(shí)內(nèi)存中可能還是原來(lái)的舊值,因此無(wú)法保證可見(jiàn)性。

另外,通過(guò)synchronized和Lock也能夠保證可見(jiàn)性,synchronized和Lock能保證同一時(shí)刻只有一個(gè)線程獲取鎖然后執(zhí)行同步代碼,并且在釋放鎖之前會(huì)將對(duì)變量的修改刷新到主存當(dāng)中。因此可以保證可見(jiàn)性。

3.有序性

在Java內(nèi)存模型中,允許編譯器和處理器對(duì)指令進(jìn)行重排序,但是重排序過(guò)程不會(huì)影響到單線程程序的執(zhí)行,卻會(huì)影響到多線程并發(fā)執(zhí)行的正確性。

在Java里面,可以通過(guò)volatile關(guān)鍵字來(lái)保證一定的“有序性”(具體原理在下一節(jié)講述)。另外可以通過(guò)synchronized和Lock來(lái)保證有序性,很顯然,synchronized和Lock保證每個(gè)時(shí)刻是有一個(gè)線程執(zhí)行同步代碼,相當(dāng)于是讓線程順序執(zhí)行同步代碼,自然就保證了有序性。

另外,Java內(nèi)存模型具備一些先天的“有序性”,即不需要通過(guò)任何手段就能夠得到保證的有序性,這個(gè)通常也稱為 happens-before 原則。如果兩個(gè)操作的執(zhí)行次序無(wú)法從happens-before原則推導(dǎo)出來(lái),那么它們就不能保證它們的有序性,虛擬機(jī)可以隨意地對(duì)它們進(jìn)行重排序。

http://www.cnblogs.com/dolphin0520/p/3920373.html

建議:

1、Java Memory Mode:JMM描述了java線程如何通過(guò)內(nèi)存進(jìn)行交互,了解happens-before,synchronized,voliatile & final

2、Locks % Condition:鎖機(jī)制和等待條件的高層實(shí)現(xiàn) java.util,concurrent.locks

3、線程安全性:原子性與可見(jiàn)性,死鎖等

4、多線程常用的交互模型

· Producer-Consumer模型

· Read-Write Lock模型

· Future模型

· Worker Thread模型

5、Java5中并發(fā)編程工具:java.util.concurrent 線程池ExcutorService Callable&Future BlockingQueue

6、推薦書本:CoreJava & JavaConcurrency In Practice

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容