欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:Java之線程篇三

柚子快報激活碼778899分享:Java之線程篇三

http://yzkb.51969.com/

???????

目錄

線程狀態(tài)

觀察線程的所有狀態(tài)

線程狀態(tài)及其描述

線程狀態(tài)轉(zhuǎn)換

代碼示例1

代碼示例2

線程安全?

概念

線程不安全的代碼示例

線程不安全的原因

線程安全的代碼示例-加鎖

synchronized關(guān)鍵字

synchronized的特性

小結(jié)

形成死鎖的四個必要條件

synchronized的使用示例

Java標(biāo)準(zhǔn)庫中的線程安全類

線程狀態(tài)

觀察線程的所有狀態(tài)

線程的狀態(tài)是一個枚舉類型 Thread.State

public class Demo11 {

public static void main(String[] args) {

for(Thread.State state:Thread.State.values())

System.out.println(state);

}

}

運(yùn)行結(jié)果

線程狀態(tài)及其描述

NEW:Thread對象已經(jīng)有了,但是start方法還沒調(diào)用;

RUNNABLE:就緒狀態(tài),線程已經(jīng)在CPU上執(zhí)行了/線程正在排隊等待執(zhí)行(即工作中或即將開始工作);

TERMINATED:Thread對象還在,但是內(nèi)核中的下線程已經(jīng)沒了,即工作完成了;

TIMED_WARTING:阻塞狀態(tài),由于sleep這種固定時間的方式產(chǎn)生的阻塞;

WAITING:阻塞,由于wait這種不固定時間的方式產(chǎn)生的阻塞;

BLOCKED:阻塞,由于鎖競爭導(dǎo)致的阻塞。

線程狀態(tài)轉(zhuǎn)換

代碼示例1

public class Demo11 {

public static void main(String[] args) {

Object object=new Object();

Thread t1=new Thread(new Runnable() {

@Override

public void run() {

synchronized (object){

while(true){

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

}

},"t1");

t1.start();

Thread t2=new Thread(new Runnable() {

@Override

public void run() {

synchronized (object){

System.out.println("hello");

}

}

},"t2");

t2.start();

}

}

通過jconsole可以看到t1的狀態(tài)是TIMED_WAITING,t2的狀態(tài)是BLOCKED。

代碼示例2

public class Demo11 {

public static void main(String[] args) {

Object object=new Object();

Thread t1=new Thread(new Runnable() {

@Override

public void run() {

synchronized (object){

while(true){

try {

object.wait();

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

}

},"t1");

t1.start();

}

}

通過jconsole可以看到t1的狀態(tài)是WAITING.

小結(jié)

BLOCKED表示等待獲取鎖,WAITING和TIMED_WAITING表示等待其它線程發(fā)來通知;

TIMED_WAITING線程在等待喚醒,但設(shè)置了時限;

WAITING線程在無限等待喚醒。

線程安全?

概念

如果多線程環(huán)境下代碼運(yùn)行的結(jié)果是符合我們預(yù)期的,即在單線程環(huán)境應(yīng)該的結(jié)果,則說這個程序是線程安全的。

線程不安全的代碼示例

public class Demo12 {

private static int count=0;

public static void main(String[] args) throws InterruptedException {

Thread t1=new Thread(()->{

for (int i = 0; i < 50000; i++) {

count++;

}

});

Thread t2=new Thread(()->{

for (int i = 0; i < 50000; i++) {

count++;

}

});

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println("count: "+count);

}

}

運(yùn)行結(jié)果

結(jié)果與預(yù)期結(jié)果不一致且差別很大,顯然上述代碼是線程不安全的。

線程不安全的原因

1.修改共享數(shù)據(jù)

上述代碼涉及到多線程(兩個及兩個以上的線程)針對同一個變量count進(jìn)行修改。

2.原子性

一條Java語句不一定是原子的,也不一定只是一條指令。

比如count++,其實是由三步操作組成的:

1.從內(nèi)存中把數(shù)據(jù)讀取到CPU;

2.對變量count進(jìn)行++;

3.把數(shù)據(jù)寫回到內(nèi)存。

如果一個線程正在對一個變量操作,中途其它線程插入進(jìn)來了,如果這個操作被打斷,結(jié)果就可能是錯誤的。

3.可見性

可見性指, 一個線程對共享變量值的修改,能夠及時地被其他線程看到.

Java 內(nèi)存模型 (JMM): Java虛擬機(jī)規(guī)范中定義了Java內(nèi)存模型.? 目的是屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問差異,以實現(xiàn)讓Java程序在各種平臺下都能達(dá)到一致的并發(fā)效果.

線程之間的共享變量存在 主內(nèi)存 (Main Memory).? 每一個線程都有自己的 "工作內(nèi)存" (Working Memory) .? 當(dāng)線程要讀取一個共享變量的時候, 會先把變量從主內(nèi)存拷貝到工作內(nèi)存, 再從工作內(nèi)存讀取數(shù)據(jù).? 當(dāng)線程要修改一個共享變量的時候, 也會先修改工作內(nèi)存中的副本, 再同步回主內(nèi)存.?

由于每個線程有自己的工作內(nèi)存, 這些工作內(nèi)存中的內(nèi)容相當(dāng)于同一個共享變量的 "副本". 此時修改線程1 的工作內(nèi)存中的值, 線程2 的工作內(nèi)存不一定會及時變化.

4.指令重排序

如果是在單線程情況下,JVM、CPU指令集會對其進(jìn)行優(yōu)化,比如,原來是按1->2->3的方式執(zhí)行,優(yōu)化后可能會按 1->3->2的方式執(zhí)行,也是沒問題,可以少跑一次前臺。這種叫做指令重排序。 編譯器對于指令重排序的前提是 "保持邏輯不發(fā)生變化". 這一點在單線程環(huán)境下比較容易判斷, 但 是在多線程環(huán)境下就沒那么容易了, 多線程的代碼執(zhí)行復(fù)雜程度更高, 編譯器很難在編譯階段對代 碼的執(zhí)行效果進(jìn)行預(yù)測, 因此激進(jìn)的重排序很容易導(dǎo)致優(yōu)化后的邏輯和之前不等價.

線程安全的代碼示例-加鎖

public class Demo12 {

private static int count=0;

public static void main(String[] args) throws InterruptedException {

Object locker=new Object();

Thread t1=new Thread(()->{

for (int i = 0; i < 50000; i++) {

synchronized (locker) {

count++;

}

}

});

Thread t2=new Thread(()->{

for (int i = 0; i < 50000; i++) {

synchronized (locker) {

count++;

}

}

});

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println("count: "+count);

}

}

運(yùn)行結(jié)果

synchronized關(guān)鍵字

synchronized的特性

1)互斥

synchronized 會起到互斥效果, 某個線程執(zhí)行到某個對象的 synchronized 中時, 其他線程如果也執(zhí)行到同一個對象 synchronized 就會阻塞等待.? 進(jìn)入 synchronized 修飾的代碼塊, 相當(dāng)于 加鎖。 退出 synchronized 修飾的代碼塊, 相當(dāng)于 解鎖。

synchronized用的鎖是存在Java對象頭里的。

synchronized

的底層是使用操作系統(tǒng)的

mutex lock

實現(xiàn)的

.

2)可重入

Java

中的

synchronized

可重入鎖

,

synchronized 同步塊對同一條線程來說是可重入的,不會出現(xiàn)自己把自己鎖死的問題;

理解死鎖

一個線程沒有釋放鎖

,

然后又嘗試再次加鎖

.

// 第一次加鎖, 加鎖成功

lock();

// 第二次加鎖, 鎖已經(jīng)被占用, 阻塞等待.

lock();

按照之前對于鎖的設(shè)定

,

第二次加鎖的時候

,

就會阻塞等待

.

直到第一次的鎖被釋放

,

才能獲取到第

二個鎖

.

但是釋放第一個鎖也是由該線程來完成

,

結(jié)果這個線程已經(jīng)躺平了

,

啥都不想干了

,

也就無

法進(jìn)行解鎖操作

.

這時候就會

死鎖

.

代碼示例

static class Counter {

? ?public int count = 0;

? ?synchronized void increase() {

? ? ? ?count++;

? }

? ?synchronized void increase2() {

? ? ? ?increase();

? }

}

在上面的代碼中,?increase 和 increase2 兩個方法都加了 synchronized, 此處的 synchronized 都是針對 this 當(dāng)前對象加鎖的.? 在調(diào)用 increase2 的時候, 先加了一次鎖, 執(zhí)行到 increase 的時候, 又加了一次鎖. (上個鎖還沒釋 放, 相當(dāng)于連續(xù)加兩次鎖),這個代碼是完全沒問題的. 因為 synchronized 是可重入鎖.

小結(jié)

在可重入鎖的內(nèi)部, 包含了 "線程持有者" 和 "計數(shù)器" 兩個信息.? 如果某個線程加鎖的時候, 發(fā)現(xiàn)鎖已經(jīng)被人占用, 但是恰好占用的正是自己, 那么仍然可以繼續(xù)獲取到鎖, 并讓計數(shù)器自增.? 解鎖的時候計數(shù)器遞減為 0 的時候, 才真正釋放鎖. (才能被別的線程獲取到)

形成死鎖的四個必要條件

死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。

1.互斥條件(鎖的基本特性)

? ?當(dāng)一個線程持有一把鎖之后,另一個線程也想要獲取到鎖,就要阻塞等待。

2.不可搶占條件(鎖的基本特性)

? ?當(dāng)鎖已經(jīng)被線程1拿到之后,線程2只能等線程1主動釋放,不能強(qiáng)行搶過來。

3.請求與保持條件(代碼結(jié)構(gòu))

? ?一個線程嘗試獲取多把鎖,已經(jīng)獲取到部分?jǐn)?shù)量的鎖,但仍嘗試獲取其它線程已經(jīng)占有的鎖。

4.循環(huán)等待/環(huán)路等待(代碼結(jié)構(gòu))

? ?等待的依賴關(guān)系,形成了環(huán)。

這四個條件同時滿足時,系統(tǒng)中就可能發(fā)生死鎖。

解決死鎖的方法通常包括死鎖預(yù)防、死鎖避免、死鎖檢測和死鎖恢復(fù)等策略。?

比如包括調(diào)整代碼結(jié)構(gòu),避免循環(huán)等待;對鎖進(jìn)行編號,先加編號大的鎖或編號小的鎖。

synchronized的使用示例

?synchronized 本質(zhì)上要修改指定對象的 "對象頭". 從使用角度來看, synchronized 也勢必要搭配一個具體的對象來使用.

1.直接修飾普通方法

public class SynchronizedDemo {

? ?public synchronized void methond() {

? }

}

2.直接修飾靜態(tài)方法

public class SynchronizedDemo {

? ?public synchronized static void method() {

? }

}

3.修飾代碼塊

鎖當(dāng)前對象

public class SynchronizedDemo {

? ?public void method() {

? ? ? ?synchronized (this) {

? ? ? ? ? ?

? ? ? }

? }

}

鎖類對象

public class SynchronizedDemo {

? ?public void method() {

? ? ? ?synchronized (SynchronizedDemo.class) {

? ? ? }

? }

}

我們重點要理解,synchronized 鎖的是什么. 兩個線程競爭同一把鎖, 才會產(chǎn)生阻塞等待.? 兩個線程分別嘗試獲取兩把不同的鎖, 不會產(chǎn)生競爭.

Java標(biāo)準(zhǔn)庫中的線程安全類

Java

標(biāo)準(zhǔn)庫中很多都是線程不安全的

.

這些類可能會涉及到多線程修改共享數(shù)據(jù)

,

又沒有任何加鎖措施

.

ArrayList

LinkedList

HashMap

TreeMap

HashSet

TreeSet

StringBuilder

但是還有一些是線程安全的

.

使用了一些鎖機(jī)制來控制

.

Vector (

不推薦使用

)

HashTable (

不推薦使用

)

ConcurrentHashMap

StringBuffer

我們可以看到,例如StringBuffer類的成員,有不少是加鎖的:

柚子快報激活碼778899分享:Java之線程篇三

http://yzkb.51969.com/

相關(guān)鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19458258.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄