成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Java011-多線程

gekylin / 1920人閱讀

摘要:多線程進(jìn)程正在進(jìn)行中的程序。所以容易出現(xiàn)線程安全問(wèn)題。等待喚醒機(jī)制涉及的方法將同步中的線程處于凍結(jié)狀態(tài)。返回該線程的字符串表示形式,包括線程名稱優(yōu)先級(jí)和線程組。暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。

多線程:
進(jìn)程:正在進(jìn)行中的程序。其實(shí)進(jìn)程就是一個(gè)應(yīng)用程序運(yùn)行時(shí)的內(nèi)存分配空間。
線程:其實(shí)就是進(jìn)程中一個(gè)程序執(zhí)行控制單元,一條執(zhí)行路徑。進(jìn)程負(fù)責(zé)的是應(yīng)用程序的空間的標(biāo)示。線程負(fù)責(zé)的是應(yīng)用程序的執(zhí)行順序。

一個(gè)進(jìn)程至少有一個(gè)線程在運(yùn)行,當(dāng)一個(gè)進(jìn)程中出現(xiàn)多個(gè)線程時(shí),就稱這個(gè)應(yīng)用程序是多線程應(yīng)用程序,每個(gè)線程在棧區(qū)中都有自己的執(zhí)行空間,自己的方法區(qū)、自己的變量。
jvm在啟動(dòng)的時(shí),首先有一個(gè)主線程,負(fù)責(zé)程序的執(zhí)行,調(diào)用的是main函數(shù)。主線程執(zhí)行的代碼都在main方法中。
當(dāng)產(chǎn)生垃圾時(shí),收垃圾的動(dòng)作,是不需要主線程來(lái)完成,因?yàn)檫@樣,會(huì)出現(xiàn)主線程中的代碼執(zhí)行會(huì)停止,會(huì)去運(yùn)行垃圾回收器代碼,效率較低,所以由多帶帶一個(gè)線程來(lái)負(fù)責(zé)垃圾回收。

隨機(jī)性的原理:因?yàn)閏pu的快速切換造成,哪個(gè)線程獲取到了cpu的執(zhí)行權(quán),哪個(gè)線程就執(zhí)行。

返回當(dāng)前線程的名稱:Thread.currentThread().getName()
線程的名稱是由:Thread-編號(hào)定義的。編號(hào)從0開(kāi)始。
線程要運(yùn)行的代碼都統(tǒng)一存放在了run方法中。

線程要運(yùn)行必須要通過(guò)類中指定的方法開(kāi)啟。start方法。(啟動(dòng)后,就多了一條執(zhí)行路徑)
start方法:1)、啟動(dòng)了線程;2)、讓jvm調(diào)用了run方法。

創(chuàng)建線程的第一種方式:繼承Thread ,由子類復(fù)寫(xiě)run方法。
步驟:
1,定義類繼承Thread類;
2,目的是復(fù)寫(xiě)run方法,將要讓線程運(yùn)行的代碼都存儲(chǔ)到run方法中;
3,通過(guò)創(chuàng)建Thread類的子類對(duì)象,創(chuàng)建線程對(duì)象;
4,調(diào)用線程的start方法,開(kāi)啟線程,并執(zhí)行run方法。

線程狀態(tài):
被創(chuàng)建:start()
運(yùn)行:具備執(zhí)行資格,同時(shí)具備執(zhí)行權(quán);
凍結(jié):sleep(time),wait()—notify()喚醒;線程釋放了執(zhí)行權(quán),同時(shí)釋放執(zhí)行資格;
臨時(shí)阻塞狀態(tài):線程具備cpu的執(zhí)行資格,沒(méi)有cpu的執(zhí)行權(quán);
消亡:stop()

創(chuàng)建線程的第二種方式:實(shí)現(xiàn)一個(gè)接口Runnable。
步驟:
1,定義類實(shí)現(xiàn)Runnable接口。
2,覆蓋接口中的run方法(用于封裝線程要運(yùn)行的代碼)。
3,通過(guò)Thread類創(chuàng)建線程對(duì)象;
4,將實(shí)現(xiàn)了Runnable接口的子類對(duì)象作為實(shí)際參數(shù)傳遞給Thread類中的構(gòu)造函數(shù)。
為什么要傳遞呢?因?yàn)橐尵€程對(duì)象明確要運(yùn)行的run方法所屬的對(duì)象。
5,調(diào)用Thread對(duì)象的start方法。開(kāi)啟線程,并運(yùn)行Runnable接口子類中的run方法。
Ticket t = new Ticket();
/*
直接創(chuàng)建Ticket對(duì)象,并不是創(chuàng)建線程對(duì)象。
因?yàn)閯?chuàng)建對(duì)象只能通過(guò)new Thread類,或者new Thread類的子類才可以。
所以最終想要?jiǎng)?chuàng)建線程。既然沒(méi)有了Thread類的子類,就只能用Thread類。
*/
Thread t1 = new Thread(t); //創(chuàng)建線程。
/*
只要將t作為Thread類的構(gòu)造函數(shù)的實(shí)際參數(shù)傳入即可完成線程對(duì)象和t之間的關(guān)聯(lián)
為什么要將t傳給Thread類的構(gòu)造函數(shù)呢?其實(shí)就是為了明確線程要運(yùn)行的代碼run方法。
*/
t1.start();

為什么要有Runnable接口的出現(xiàn)?
1:通過(guò)繼承Thread類的方式,可以完成多線程的建立。但是這種方式有一個(gè)局限性,如果一個(gè)類已經(jīng)有了自己的父類,就不可以繼承Thread類,因?yàn)閖ava單繼承的局限性。
可是該類中的還有部分代碼需要被多個(gè)線程同時(shí)執(zhí)行。這時(shí)怎么辦呢?
只有對(duì)該類進(jìn)行額外的功能擴(kuò)展,java就提供了一個(gè)接口Runnable。這個(gè)接口中定義了run方法,其實(shí)run方法的定義就是為了存儲(chǔ)多線程要運(yùn)行的代碼。
所以,通常創(chuàng)建線程都用第二種方式。
因?yàn)閷?shí)現(xiàn)Runnable接口可以避免單繼承的局限性。

2:其實(shí)是將不同類中需要被多線程執(zhí)行的代碼進(jìn)行抽取。將多線程要運(yùn)行的代碼的位置多帶帶定義到接口中。為其他類進(jìn)行功能擴(kuò)展提供了前提。
所以Thread類在描述線程時(shí),內(nèi)部定義的run方法,也來(lái)自于Runnable接口。

實(shí)現(xiàn)Runnable接口可以避免單繼承的局限性。而且,繼承Thread,是可以對(duì)Thread類中的方法,進(jìn)行子類復(fù)寫(xiě)的。但是不需要做這個(gè)復(fù)寫(xiě)動(dòng)作的話,只為定義線程代碼存放位置,實(shí)現(xiàn)Runnable接口更方便一些。所以Runnable接口將線程要執(zhí)行的任務(wù)封裝成了對(duì)象。

//面試
new Thread(new Runnable(){ //匿名
public void run(){
System.out.println("runnable run");
}
})
{
public void run(){
System.out.println("subthread run");
}

}.start(); //結(jié)果:subthread run

Try {
Thread.sleep(10);
}catch(InterruptedException e){}// 當(dāng)刻意讓線程稍微停一下,模擬cpu切換情況。

多線程安全問(wèn)題的原因:
通過(guò)圖解:發(fā)現(xiàn)一個(gè)線程在執(zhí)行多條語(yǔ)句時(shí),并運(yùn)算同一個(gè)數(shù)據(jù)時(shí),在執(zhí)行過(guò)程中,其他線程參與進(jìn)來(lái),并操作了這個(gè)數(shù)據(jù)。導(dǎo)致到了錯(cuò)誤數(shù)據(jù)的產(chǎn)生。

涉及到兩個(gè)因素:
1,多個(gè)線程在操作共享數(shù)據(jù)。
2,有多條語(yǔ)句對(duì)共享數(shù)據(jù)進(jìn)行運(yùn)算。
原因:這多條語(yǔ)句,在某一個(gè)時(shí)刻被一個(gè)線程執(zhí)行時(shí),還沒(méi)有執(zhí)行完,就被其他線程執(zhí)行了。

解決安全問(wèn)題的原理:
只要將操作共享數(shù)據(jù)的語(yǔ)句在某一時(shí)段讓一個(gè)線程執(zhí)行完,在執(zhí)行過(guò)程中,其他線程不能進(jìn)來(lái)執(zhí)行就可以解決這個(gè)問(wèn)題。

如何進(jìn)行多句操作共享數(shù)據(jù)代碼的封裝呢?
java中提供了一個(gè)解決方式:就是同步代碼塊。
格式:
synchronized(對(duì)象) { // 任意對(duì)象都可以。這個(gè)對(duì)象就是鎖。
需要被同步的代碼;

}

同步:★★★★★
好處:解決了線程安全問(wèn)題。
弊端:相對(duì)降低性能,因?yàn)榕袛噫i需要消耗資源,產(chǎn)生了死鎖。

定義同步是有前提的:
1,必須要有兩個(gè)或者兩個(gè)以上的線程,才需要同步。
2,多個(gè)線程必須保證使用的是同一個(gè)鎖。

同步的第二種表現(xiàn)形式:
同步函數(shù):其實(shí)就是將同步關(guān)鍵字定義在函數(shù)上,讓函數(shù)具備了同步性。

同步函數(shù)是用的哪個(gè)鎖呢?
通過(guò)驗(yàn)證,函數(shù)都有自己所屬的對(duì)象this,所以同步函數(shù)所使用的鎖就是this鎖。

當(dāng)同步函數(shù)被static修飾時(shí),這時(shí)的同步用的是哪個(gè)鎖呢?
靜態(tài)函數(shù)在加載時(shí)所屬于類,這時(shí)有可能還沒(méi)有該類產(chǎn)生的對(duì)象,但是該類的字節(jié)碼文件加載進(jìn)內(nèi)存就已經(jīng)被封裝成了對(duì)象,這個(gè)對(duì)象就是該類的字節(jié)碼文件對(duì)象。
所以靜態(tài)加載時(shí),只有一個(gè)對(duì)象存在,那么靜態(tài)同步函數(shù)就使用的這個(gè)對(duì)象。
這個(gè)對(duì)象就是 類名.class

同步代碼塊和同步函數(shù)的區(qū)別?
同步代碼塊使用的鎖可以是任意對(duì)象。
同步函數(shù)使用的鎖是this,靜態(tài)同步函數(shù)的鎖是該類的字節(jié)碼文件對(duì)象。

在一個(gè)類中只有一個(gè)同步,可以使用同步函數(shù)。如果有多同步,必須使用同步代碼塊,來(lái)確定不同的鎖。所以同步代碼塊相對(duì)靈活一些。

★考點(diǎn)問(wèn)題:請(qǐng)寫(xiě)一個(gè)延遲加載的單例模式?寫(xiě)懶漢式;當(dāng)出現(xiàn)多線程訪問(wèn)時(shí)怎么解決?加同步,解決安全問(wèn)題;效率高嗎?不高;怎樣解決?通過(guò)雙重判斷的形式解決。
//懶漢式:延遲加載方式。
當(dāng)多線程訪問(wèn)懶漢式時(shí),因?yàn)閼袧h式的方法內(nèi)對(duì)共性數(shù)據(jù)進(jìn)行多條語(yǔ)句的操作。所以容易出現(xiàn)線程安全問(wèn)題。為了解決,加入同步機(jī)制,解決安全問(wèn)題。但是卻帶來(lái)了效率降低。
為了效率問(wèn)題,通過(guò)雙重判斷的形式解決。
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){ //鎖是誰(shuí)?字節(jié)碼文件對(duì)象;
if(s == null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s;
}

}

同步死鎖:通常只要將同步進(jìn)行嵌套,就可以看到現(xiàn)象。同步函數(shù)中有同步代碼塊,同步代碼塊中還有同步函數(shù)。

線程間通信:思路:多個(gè)線程在操作同一個(gè)資源,但是操作的動(dòng)作卻不一樣。
1:將資源封裝成對(duì)象。
2:將線程執(zhí)行的任務(wù)(任務(wù)其實(shí)就是run方法。)也封裝成對(duì)象。

等待喚醒機(jī)制:涉及的方法:
wait:將同步中的線程處于凍結(jié)狀態(tài)。釋放了執(zhí)行權(quán),釋放了資格。同時(shí)將線程對(duì)象存儲(chǔ)到線程池中。
notify:?jiǎn)拘丫€程池中某一個(gè)等待線程。
notifyAll:喚醒的是線程池中的所有線程。

注意:
1:這些方法都需要定義在同步中。
2:因?yàn)檫@些方法必須要標(biāo)示所屬的鎖。
你要知道 A鎖上的線程被wait了,那這個(gè)線程就相當(dāng)于處于A鎖的線程池中,只能A鎖的notify喚醒。
3:這三個(gè)方法都定義在Object類中。為什么操作線程的方法定義在Object類中?
因?yàn)檫@三個(gè)方法都需要定義同步內(nèi),并標(biāo)示所屬的同步鎖,既然被鎖調(diào)用,而鎖又可以是任意對(duì)象,那么能被任意對(duì)象調(diào)用的方法一定定義在Object類中。

wait和sleep區(qū)別: 分析這兩個(gè)方法:從執(zhí)行權(quán)和鎖上來(lái)分析:
wait:可以指定時(shí)間也可以不指定時(shí)間。不指定時(shí)間,只能由對(duì)應(yīng)的notify或者notifyAll來(lái)喚醒。
sleep:必須指定時(shí)間,時(shí)間到自動(dòng)從凍結(jié)狀態(tài)轉(zhuǎn)成運(yùn)行狀態(tài)(臨時(shí)阻塞狀態(tài))。
wait:線程會(huì)釋放執(zhí)行權(quán),而且線程會(huì)釋放鎖。
Sleep:線程會(huì)釋放執(zhí)行權(quán),但不是不釋放鎖。

線程的停止:通過(guò)stop方法就可以停止線程。但是這個(gè)方式過(guò)時(shí)了。
停止線程:原理就是:讓線程運(yùn)行的代碼結(jié)束,也就是結(jié)束run方法。
怎么結(jié)束run方法?一般run方法里肯定定義循環(huán)。所以只要結(jié)束循環(huán)即可。
第一種方式:定義循環(huán)的結(jié)束標(biāo)記。
第二種方式:如果線程處于了凍結(jié)狀態(tài),是不可能讀到標(biāo)記的,這時(shí)就需要通過(guò)Thread類中的interrupt方法,將其凍結(jié)狀態(tài)強(qiáng)制清除。讓線程恢復(fù)具備執(zhí)行資格的狀態(tài),讓線程可以讀到標(biāo)記,并結(jié)束。

---------< java.lang.Thread >----------
interrupt():中斷線程。
setPriority(int newPriority):更改線程的優(yōu)先級(jí)。
getPriority():返回線程的優(yōu)先級(jí)。
toString():返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級(jí)和線程組。
Thread.yield():暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。
setDaemon(true):將該線程標(biāo)記為守護(hù)線程或用戶線程。將該線程標(biāo)記為守護(hù)線程或用戶線程。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時(shí),Java 虛擬機(jī)退出。該方法必須在啟動(dòng)線程前調(diào)用。
join:臨時(shí)加入一個(gè)線程的時(shí)候可以使用join方法。

當(dāng)A線程執(zhí)行到了B線程的join方式。A線程處于凍結(jié)狀態(tài),釋放了執(zhí)行權(quán),B開(kāi)始執(zhí)行。A什么時(shí)候執(zhí)行呢?只有當(dāng)B線程運(yùn)行結(jié)束后,A才從凍結(jié)狀態(tài)恢復(fù)運(yùn)行狀態(tài)執(zhí)行。

Lock接口:多線程在JDK1.5版本升級(jí)時(shí),推出一個(gè)接口Lock接口。
解決線程安全問(wèn)題使用同步的形式,(同步代碼塊,要么同步函數(shù))其實(shí)最終使用的都是鎖機(jī)制。

到了后期版本,直接將鎖封裝成了對(duì)象。線程進(jìn)入同步就是具備了鎖,執(zhí)行完,離開(kāi)同步,就是釋放了鎖。
在后期對(duì)鎖的分析過(guò)程中,發(fā)現(xiàn),獲取鎖,或者釋放鎖的動(dòng)作應(yīng)該是鎖這個(gè)事物更清楚。所以將這些動(dòng)作定義在了鎖當(dāng)中,并把鎖定義成對(duì)象。

所以同步是隱示的鎖操作,而Lock對(duì)象是顯示的鎖操作,它的出現(xiàn)就替代了同步。

在之前的版本中使用Object類中wait、notify、notifyAll的方式來(lái)完成的。那是因?yàn)橥街械逆i是任意對(duì)象,所以操作鎖的等待喚醒的方法都定義在Object類中。

而現(xiàn)在鎖是指定對(duì)象Lock。所以查找等待喚醒機(jī)制方式需要通過(guò)Lock接口來(lái)完成。而Lock接口中并沒(méi)有直接操作等待喚醒的方法,而是將這些方式又多帶帶封裝到了一個(gè)對(duì)象中。這個(gè)對(duì)象就是Condition,將Object中的三個(gè)方法進(jìn)行多帶帶的封裝。并提供了功能一致的方法 await()、signal()、signalAll()體現(xiàn)新版本對(duì)象的好處。

< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();

class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {

 lock.lock();
 try {
   while (count == items.length)
     notFull.await();
   items[putptr] = x;
   if (++putptr == items.length) putptr = 0;
   ++count;
   notEmpty.signal();
 }

finally {

   lock.unlock();
 }

}
public Object take() throws InterruptedException {

 lock.lock();
 try {
   while (count == 0)
     notEmpty.await();
   Object x = items[takeptr];
   if (++takeptr == items.length) takeptr = 0;
   --count;
   notFull.signal();
   return x;
 }

finally {

   lock.unlock();
 }

}

}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/73214.html

相關(guān)文章

  • 原理剖析(第 011 篇)Netty之服務(wù)端啟動(dòng)工作原理分析(下)

    摘要:原理剖析第篇之服務(wù)端啟動(dòng)工作原理分析下一大致介紹由于篇幅過(guò)長(zhǎng)難以發(fā)布,所以本章節(jié)接著上一節(jié)來(lái)的,上一章節(jié)為原理剖析第篇之服務(wù)端啟動(dòng)工作原理分析上那么本章節(jié)就繼續(xù)分析的服務(wù)端啟動(dòng),分析的源碼版本為二三四章節(jié)請(qǐng)看上一章節(jié)詳見(jiàn)原理剖析第篇之 原理剖析(第 011 篇)Netty之服務(wù)端啟動(dòng)工作原理分析(下) - 一、大致介紹 1、由于篇幅過(guò)長(zhǎng)難以發(fā)布,所以本章節(jié)接著上一節(jié)來(lái)的,上一章節(jié)為【原...

    Tikitoo 評(píng)論0 收藏0
  • SpringCloud(第 011 篇)電影Ribbon微服務(wù),脫離Eureka使用配置listOf

    摘要:第篇電影微服務(wù),脫離使用配置進(jìn)行客戶端負(fù)載均衡調(diào)度一大致介紹通過(guò)嘗試脫離服務(wù)治理框架,脫離生態(tài)圈,單獨(dú)操作客戶端負(fù)載均衡調(diào)度本章節(jié)僅僅只是使用了來(lái)測(cè)試客戶端負(fù)載均衡算法二實(shí)現(xiàn)步驟添加引用包模塊客 SpringCloud(第 011 篇)電影Ribbon微服務(wù),脫離Eureka使用配置listOfServers進(jìn)行客戶端負(fù)載均衡調(diào)度 - 一、大致介紹 1、通過(guò)嘗試脫離服務(wù)治理框架,脫離 ...

    newtrek 評(píng)論0 收藏0
  • Flink實(shí)戰(zhàn)(八) - Streaming Connectors 編程

    摘要:默認(rèn)情況下,當(dāng)數(shù)據(jù)元到達(dá)時(shí),分段接收器將按當(dāng)前系統(tǒng)時(shí)間拆分,并使用日期時(shí)間模式命名存儲(chǔ)區(qū)。如果需要,可以使用數(shù)據(jù)元或元組的屬性來(lái)確定目錄。這將調(diào)用傳入的數(shù)據(jù)元并將它們寫(xiě)入部分文件,由換行符分隔。消費(fèi)者的消費(fèi)者被稱為或等。 1 概覽 1.1 預(yù)定義的源和接收器 Flink內(nèi)置了一些基本數(shù)據(jù)源和接收器,并且始終可用。該預(yù)定義的數(shù)據(jù)源包括文件,目錄和插socket,并從集合和迭代器攝取數(shù)據(jù)...

    beita 評(píng)論0 收藏0
  • 記一次線上bug處理-mybatis一級(jí)緩存引起

    摘要:?jiǎn)栴}線上定時(shí)任務(wù)計(jì)算出的金額不對(duì)定位問(wèn)題查看日志好像也執(zhí)行了但是金額為什么和數(shù)據(jù)庫(kù)的表里的不一致再查整個(gè)的定時(shí)任務(wù)日志日切日期 問(wèn)題: 線上riskProvision定時(shí)任務(wù),計(jì)算出的金額不對(duì) 定位問(wèn)題: 查看日志 4.13 riskProvision 2017-04-13 01:10:00.009 [org.springframework.scheduling.quartz....

    sean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<