欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    1、進(jìn)程與class MyThread extends Thread { private int i = 5; @Override public void run() { System.out.println("i=" + (i--) + " threadName=" + Thread.currentThread().getName()); } }

    //測(cè)試i--與println()聯(lián)合使用時(shí)可能出現(xiàn)異常
    public class Test {
        public static void main(String[] args) {
            // 創(chuàng)建一個(gè)MyThread對(duì)象,并將該對(duì)象分別加載到五個(gè)線程中并分別給線程命名
            MyThread myThread = new MyThread();
            Thread t1 = new Thread(myThread);
            Thread t2 = new Thread(myThread);
            Thread t3 = new Thread(myThread);
            Thread t4 = new Thread(myThread);
            Thread t5 = new Thread(myThread);
            // 啟動(dòng)五個(gè)線程,myThread中的 i=5 會(huì)由5個(gè)線程共享,5個(gè)線程分別執(zhí)行 run()
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
        }
    }
    

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

    i=5 threadName=Thread-1
    i=2 threadName=Thread-5
    i=5 threadName=Thread-2
    i=4 threadName=Thread-3
    i=3 threadName=Thread-4
    

    原因: ()方法與i--聯(lián)合使用時(shí)“有可能”出現(xiàn)異常,雖然()方法在內(nèi)部是同步的,但i--的操作卻是在進(jìn)入()之前發(fā)生的,所以有發(fā)生非線程安全問題的概率。

    () 的源碼:

    public void println(String x) {
    	synchronized (this) {
    		print(x);
    		newLine();
    	}
    }
    

    解決方法:()與i--聯(lián)合使用時(shí)可能會(huì)出現(xiàn)非線程安全問題,解決方法仍是使用同步方法,即在需要同步的方法(比如上文中的run方法)前加上關(guān)鍵字。

    6、如何知道代碼段被哪個(gè)線程調(diào)用?

    System.out.println(Thread.currentThread().getName());
    

    7、線程活動(dòng)狀態(tài)

    public class XKThread extends Thread {
    	@Override
    	public void run() {
    		System.out.println("run run run is " + this.isAlive() );
    	}
    	public static void main(String[] args) {
    		XKThread xk = new XKThread();
    		System.out.println("begin ——— " + xk.isAlive());
    		xk.start();
    		System.out.println("end ————— " + xk.isAlive());
    	}
    }
    

    8、sleep()方法

    方法sleep()的作用是在指定的毫秒數(shù)內(nèi)讓當(dāng)前的正在執(zhí)行的線程休眠(暫停執(zhí)行)。

    9、如何優(yōu)雅地設(shè)置睡眠時(shí)間?

    jdk1.5后,引入了一個(gè)枚舉 ,對(duì)sleep方法提供了很好的封裝。

    比如要表達(dá)2小時(shí)22分55秒899毫秒。

    Thread.sleep(8575899L);
    TimeUnit.HOURS.sleep(2);
    TimeUnit.MINUTES.sleep(22);
    TimeUnit.SECONDS.sleep(55);
    TimeUnit.MILLISECONDS.sleep(899);
    

    可以看到表達(dá)的含義更清晰,更優(yōu)雅。

    10、停止線程

    run()方法執(zhí)行完成,自然終止。

    stop()方法,()以及()都是過期作廢方法,使用它們結(jié)果不可預(yù)期。

    大多數(shù)停止一個(gè)線程的操作使用.()等于說給線程打一個(gè)停止的標(biāo)記,此方法不會(huì)去終止一個(gè)正在運(yùn)行的線程,需要加入一個(gè)判斷才能可以完成線程的停止。

    11、和的區(qū)別

    :判斷當(dāng)前線程是否已經(jīng)中斷,會(huì)清除狀態(tài)。

    :判斷線程是否已經(jīng)中斷,不會(huì)清除狀態(tài)。

    12、yield

    放棄當(dāng)前CPU資源,將它讓給其他的任務(wù)占用CPU執(zhí)行時(shí)間。但放棄的時(shí)間不確定,有可能剛剛放棄,馬上又獲得CPU時(shí)間片。

    測(cè)試代碼:(cpu獨(dú)占時(shí)間片)

    public class XKThread extends Thread {
    	@Override
    	public void run() {
    		long beginTime = System.currentTimeMillis();
    		int count = 0;
    		for (int i = 0; i < 50000000; i++) {
    			count = count + (i + 1);
    		}
    		long endTime = System.currentTimeMillis();
    		System.out.println("?用時(shí) = " + (endTime - beginTime) + " 毫秒! ");
    	}
    	public static void main(String[] args) {
    		XKThread xkThread = new XKThread();
    		xkThread.start();
    	}
    }
    

    輸出結(jié)果:

    用時(shí) = 20 毫秒!
    

    加入yield再來測(cè)試。(CPU讓給其他資源導(dǎo)致速度變慢)

    public class XKThread extends Thread {
    	@Override
    	public void run() {
    		long beginTime = System.currentTimeMillis();
    		int count = 0;
    		for (int i = 0; i < 50000000; i++) {
    			Thread.yield();//加入yield
    			count = count + (i + 1);
    		}
    		long endTime = System.currentTimeMillis();
    		System.out.println("?用時(shí) = " + (endTime - beginTime) + " 毫秒! ");
    	}
    	public static void main(String[] args) {
    		XKThread xkThread = new XKThread();
    		xkThread.start();
    	}
    }
    

    結(jié)果:

    用時(shí) = 38424 毫秒!
    

    13、線程的優(yōu)先級(jí)

    在操作系統(tǒng)中,線程可以劃分優(yōu)先級(jí),優(yōu)先級(jí)較高的線程得到cpu資源比較多,也就是cpu優(yōu)先執(zhí)行優(yōu)先級(jí)較高的線程對(duì)象中的任務(wù),但是不能保證一定優(yōu)先級(jí)高,就先執(zhí)行。

    Java的優(yōu)先級(jí)分為1~10個(gè)等級(jí),數(shù)字越大優(yōu)先級(jí)越高,默認(rèn)優(yōu)先級(jí)大小為5。超出范圍則拋出:java.lang.tion。

    14、優(yōu)先級(jí)繼承特性

    線程的優(yōu)先級(jí)具有繼承性,比如a線程啟動(dòng)b線程,b線程與a優(yōu)先級(jí)是一樣的。

    15、誰跑的更快?

    設(shè)置優(yōu)先級(jí)高低兩個(gè)線程,累加數(shù)字,看誰跑的快,上代碼。

    public class Run extends Thread{
    	public static void main(String[] args) {
    		try {
    			ThreadLow low = new ThreadLow();
    			low.setPriority(2);
    			low.start();
    			ThreadHigh high = new ThreadHigh();
    			high.setPriority(8);
    			high.start();
    			Thread.sleep(2000);
    			low.stop();
    			high.stop();
    			System.out.println("low = " + low.getCount());
    			System.out.println("high = " + high.getCount());
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    class ThreadHigh extends Thread {
    	private int count = 0;
    	public int getCount() {
    		return count;
    	}
    	@Override
    	public void run() {
    		while (true) {
    			count++;
    		}
    	}
    }
    class ThreadLow extends Thread {
    	private int count = 0;
    	public int getCount() {
    		return count;
    	}
    	
    	@Override
    	public void run() {
    		while (true) {
    			count++;
    		}
    	}
    }
    

    結(jié)果:

    low = 1193854568
    high = 1204372373
    

    16、線程種類

    Java線程有兩種,一種是用戶線程,一種是守護(hù)線程()。

    17、守護(hù)線程 17.1 守護(hù)線程的特點(diǎn)

    守護(hù)線程是一個(gè)比較特殊的線程,主要被用做程序中后臺(tái)調(diào)度以及支持性工作。當(dāng)Java虛擬機(jī)中不存在非守護(hù)線程時(shí),守護(hù)線程才會(huì)隨著JVM一同結(jié)束工作。

    17.2 Java中典型的守護(hù)線程

    GC(垃圾回收器)

    17.3 如何設(shè)置守護(hù)線程

    .(true)

    PS:屬性需要在啟動(dòng)線程之前設(shè)置,不能再啟動(dòng)后設(shè)置。

    17.4 Java虛擬機(jī)退出時(shí)線程中的塊一定會(huì)執(zhí)行?

    Java虛擬機(jī)退出時(shí),線程中的塊并不一定會(huì)執(zhí)行。

    代碼示例:

    public class XKDaemon {
    	public static void main(String[] args) {
    		Thread thread = new Thread(new DaemonRunner(),"xkDaemonRunner");
    		thread.setDaemon(true);
    		thread.start();
    	}
    	
    	static class DaemonRunner implements Runnable {
    		@Override
    		public void run() {
    			try {
    				SleepUtils.sleep(10);
    			} finally {
    				System.out.println("Java?小咖秀 daemonThread finally run …");
    			}
    		}
    	}
    }
    

    結(jié)果:

    
    

    沒有任何的輸出,說明沒有執(zhí)行。

    18、設(shè)置線程上下文類加載器

    獲取線程上下文類加載器

    public ClassLoader getContextClassLoader()
    

    設(shè)置線程類加載器(可以打破Java類加載器的父類委托機(jī)制)

    public void setContextClassLoader(ClassLoader cl)
    

    19、join

    join是指把指定的線程加入到當(dāng)前線程,比如join某個(gè)線程a,會(huì)讓當(dāng)前線程b進(jìn)入等待,直到a的生命周期結(jié)束,此期間b線程是處于狀態(tài)。

    20、 20.1 什么是?

    關(guān)鍵字可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的策略來防止線程干擾和內(nèi)存一致性錯(cuò)誤,如果一個(gè)對(duì)象是對(duì)多個(gè)線程可見的,那么對(duì)該對(duì)象的所有讀寫都將通過同步的方式來進(jìn)行。

    20.2、包括哪兩個(gè)jvm重要的指令?

    enter和 exit

    20.3 關(guān)鍵字用法?

    可以用于對(duì)代碼塊或方法的修飾

    20.4 鎖的是什么? 被修飾情況被鎖對(duì)象

    普通同步方法

    當(dāng)前實(shí)例對(duì)象

    靜態(tài)同步方法

    當(dāng)前類的Class對(duì)象

    同步方法塊

    括號(hào)里配置的對(duì)象

    21、Java對(duì)象的組成 Java對(duì)象在內(nèi)存中的保存格式

    內(nèi)容長(zhǎng)度(32/64位JVM)說明

    對(duì)象頭

    Mark Word

    32/64bit

    存儲(chǔ)對(duì)象的或者鎖信息等。當(dāng)這個(gè)對(duì)象被關(guān)鍵字當(dāng)成同步鎖時(shí),圍繞這個(gè)鎖的一系列操作都和Mark Word有關(guān)。

    指向類的指針

    32/64bit

    即指向當(dāng)前對(duì)象的類的元數(shù)據(jù)的指針,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。并不是所有的虛擬機(jī)實(shí)現(xiàn)都必須在對(duì)象數(shù)據(jù)上保留類型指針,換句話說查找對(duì)象的元數(shù)據(jù)信息并不一定要經(jīng)過對(duì)象本身。

    數(shù)組長(zhǎng)度

    32/32bit

    只有數(shù)組對(duì)象保存了這部分?jǐn)?shù)據(jù)

    實(shí)例數(shù)據(jù)

    實(shí)例數(shù)據(jù)部分是對(duì)象真正存儲(chǔ)的有效信息,也就是我們?cè)诔绦虼a里面所定義的各種類型的字段內(nèi)容,無論是從父類繼承下來的,還是在子類中定義的都需要記錄下來。 這部分的存儲(chǔ)順序會(huì)受到虛擬機(jī)分配策略參數(shù)(e)和字段在Java源碼中定義順序的影響。

    對(duì)齊填充字節(jié)

    因?yàn)镴VM要求Java的對(duì)象占的內(nèi)存大小應(yīng)該是8bit的倍數(shù),所以后面有幾個(gè)字節(jié)用于把對(duì)象的大小補(bǔ)齊至8bit的倍數(shù),沒有特別的功能。

    用的鎖是存在Java對(duì)象頭里的。對(duì)象如果是數(shù)組類型,虛擬機(jī)用3個(gè)字寬存儲(chǔ)對(duì)象頭,如果對(duì)象是非數(shù)組類型,用2字寬存儲(chǔ)對(duì)象頭。

    Tips:32位虛擬機(jī)中一個(gè)字寬等于4字節(jié)。

    32位JVM的Mark Word默認(rèn)存儲(chǔ)結(jié)構(gòu):

    鎖狀態(tài)是否偏向鎖2bit鎖標(biāo)志位

    無鎖狀態(tài)

    對(duì)象的

    對(duì)象分代年齡

    0

    01

    21.1 Mark Word的狀態(tài)變化

    Mark Word存儲(chǔ)的數(shù)據(jù)會(huì)隨著鎖標(biāo)志位的變化而變化。在32位JVM中長(zhǎng)度是這么存的:

    鎖狀態(tài)

    是否是偏向鎖鎖標(biāo)志位

    無鎖

    對(duì)象的

    對(duì)象分代年齡

    0

    01

    偏向鎖

    線程ID

    Epoch

    對(duì)象分代年齡

    1

    01

    輕量級(jí)鎖

    指向棧中鎖記錄的指針

    00

    重量級(jí)鎖

    指向互斥量(重量級(jí)鎖)的指針

    10

    GC標(biāo)記

    11

    64位JVM下,Mark Word是64位大小的。

    鎖狀態(tài)

    分代年齡

    偏向鎖

    標(biāo)志位

    無鎖

    0

    01

    偏向鎖

    (54bit) Epoch(2bit)

    1

    01

    JVM一般是這樣使用鎖和Mark Word的:

    無鎖狀態(tài)時(shí),這就是一個(gè)普通的對(duì)象,Mark Word記錄對(duì)象的,鎖標(biāo)志位是01,是否偏向鎖那一位是0。當(dāng)對(duì)象被當(dāng)做同步鎖并有一個(gè)線程A搶到了鎖時(shí),鎖標(biāo)志位還是01,但是否偏向鎖那一位改成1,前23bit記錄搶到鎖的線程ID,表示進(jìn)入偏向鎖狀態(tài)。當(dāng)線程A再次試圖來獲得鎖時(shí),JVM發(fā)現(xiàn)同步鎖對(duì)象的標(biāo)志位是01,是否偏向鎖是1,也就是偏向鎖狀態(tài),Mark Word中記錄的線程ID就是線程A自己的ID,表示線程A已經(jīng)獲得了這個(gè)偏向鎖,可以執(zhí)行同步鎖的代碼。當(dāng)線程B試圖獲得這個(gè)鎖時(shí),JVM發(fā)現(xiàn)同步鎖處于偏向狀態(tài),但是Mark Word中的線程id記錄的不是B,那么線程B會(huì)先用CAS操作試圖獲得鎖,這里的獲得鎖操作是有可能成功的,因?yàn)榫€程A一般不會(huì)自動(dòng)釋放偏向鎖。如果搶鎖成功,就把Mark Word里的線程ID改為線程B的ID,代表線程B獲得了這個(gè)偏向鎖,可以執(zhí)行同步鎖代碼。如果搶鎖失敗,則繼續(xù)執(zhí)行步驟5。偏向鎖狀態(tài)搶鎖失敗,代表當(dāng)前鎖有一定的競(jìng)爭(zhēng),偏向鎖將升級(jí)為輕量級(jí)鎖。JVM會(huì)在當(dāng)前線程的線程棧中開辟一塊單獨(dú)的空間,里面保存指向?qū)ο箧iMark Word的指針,同時(shí)在對(duì)象鎖Mark Word中保存指向這片空間的指針。上述兩個(gè)保存操作都是CAS操作,如果保存成功,代表線程搶到了同步鎖,就把Mark Word中的鎖標(biāo)志位改成00,可以執(zhí)行同步鎖代碼。如果保存失敗,表示搶鎖失敗,競(jìng)爭(zhēng)太激烈,繼續(xù)執(zhí)行步驟6。輕量級(jí)鎖搶鎖失敗,JVM會(huì)使用自旋鎖,自旋鎖不是一個(gè)鎖狀態(tài),只是代表不斷的重試,嘗試搶鎖。從JDK1.7開始,自旋鎖默認(rèn)啟用,自旋次數(shù)由JVM決定。如果搶鎖成功則執(zhí)行同步鎖代碼,如果失敗則繼續(xù)執(zhí)行步驟7。自旋鎖重試之后如果搶鎖依然失敗,同步鎖會(huì)升級(jí)至重量級(jí)鎖,鎖標(biāo)志位改為10。在這個(gè)狀態(tài)下,未搶到鎖的線程都會(huì)被阻塞。 22、Java鎖的種類 22.1 鎖的升降級(jí)規(guī)則

    Java SE1.6為了提高鎖的性能。引入了偏向鎖和輕量級(jí)鎖。

    Java SE1.6中鎖有4種狀態(tài)。級(jí)別從低到高依次是:無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級(jí)鎖狀態(tài)、重量級(jí)鎖狀態(tài)。

    鎖只能升級(jí)不能降級(jí)。

    22.2 偏向鎖

    大多數(shù)情況,鎖不僅不存在多線程競(jìng)爭(zhēng),而且總由同一線程多次獲得。當(dāng)一個(gè)線程訪問同步塊并獲取鎖時(shí),會(huì)在對(duì)象頭和棧幀中記錄存儲(chǔ)鎖偏向的線程ID,以后該線程在進(jìn)入和退出同步塊時(shí)不需要進(jìn)行cas操作來加鎖和解鎖,只需測(cè)試一下對(duì)象頭Mark Word里是否存儲(chǔ)著指向當(dāng)前線程的偏向鎖。如果測(cè)試成功,表示線程已經(jīng)獲得了鎖,如果失敗,則需要測(cè)試下Mark Word中偏向鎖的標(biāo)示是否已經(jīng)設(shè)置成1(表示當(dāng)前是偏向鎖),如果沒有設(shè)置,則使用cas競(jìng)爭(zhēng)鎖,如果設(shè)置了,則嘗試使用cas將對(duì)象頭的偏向鎖只限當(dāng)前線程。

    關(guān)閉偏向鎖延遲

    java6 和 7 中默認(rèn)啟用偏向鎖延遲,但是會(huì)在程序啟動(dòng)幾秒后才激活,如果需要關(guān)閉延遲,使用-XX:Delay=0。

    如何關(guān)閉偏向鎖

    JVM參數(shù)關(guān)閉偏向鎖:-XX:-=false,那么程序默認(rèn)會(huì)進(jìn)入輕量級(jí)鎖狀態(tài)。

    Tips:如果你可以確定程序的所有鎖通常情況處于競(jìng)態(tài),則可以選擇關(guān)閉。

    22.3 輕量級(jí)鎖

    線程在執(zhí)行同步塊,JVM會(huì)在當(dāng)前線程的棧幀中創(chuàng)建用于儲(chǔ)存鎖記錄的空間。并將對(duì)象頭中的Mark

    Word復(fù)制到鎖記錄中。然后線程嘗試使用 cas 將對(duì)象頭中的替換為自己鎖記錄的指針。如果成功,當(dāng)前線程獲得鎖,如果失敗,表示其他線程競(jìng)爭(zhēng)鎖,當(dāng)前線程便嘗試使用自旋來獲取鎖。

    輕量級(jí)鎖的解鎖

    輕量級(jí)鎖解鎖時(shí),會(huì)使原子操作cas將 Mark Word替換回對(duì)象頭,如果成功則表示沒有競(jìng)爭(zhēng)發(fā)生,如果失敗,表示存在競(jìng)爭(zhēng),此時(shí)鎖就會(huì)膨脹為重量級(jí)鎖。

    22.4 鎖的優(yōu)缺點(diǎn)對(duì)比 鎖優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景

    偏向鎖

    加鎖和解鎖都不需要額外的消耗,和執(zhí)行非同步方法相比僅存在納秒級(jí)的差距

    如果線程間存在鎖競(jìng)爭(zhēng),會(huì)帶來額外的鎖撤銷的消耗

    只有一個(gè)線程訪問同步塊

    輕量級(jí)鎖

    競(jìng)爭(zhēng)的線程不會(huì)阻塞,提高了程序的響應(yīng)速度

    如果始終得不到鎖競(jìng)爭(zhēng)的線程,使用自旋會(huì)消耗CPU

    追求響應(yīng)時(shí)間、同步塊執(zhí)行速度非常塊

    重量級(jí)鎖

    線程競(jìng)爭(zhēng)不使用自旋,不會(huì)消耗CPU

    線程阻塞word沒有響應(yīng)保存 等待,響應(yīng)時(shí)間慢

    追求吞吐量、同步塊執(zhí)行時(shí)間較長(zhǎng)

    23、什么是原子操作

    不可被中斷的一個(gè)或者一系列操作。

    23.1 Java如何實(shí)現(xiàn)原子操作

    Java中通過鎖和循環(huán) CAS 的方式來實(shí)現(xiàn)原子操作,JVM的CAS操作利用了處理器提供的指令來實(shí)現(xiàn)的。自旋CAS實(shí)現(xiàn)的基本思路就是循環(huán)進(jìn)行CAS操作直到成功為止。

    23.2 CAS實(shí)現(xiàn)原子操作的3大問題 什么是ABA問題

    問題:因?yàn)閏as需要在操作值的時(shí)候,檢查值有沒有變化,如果沒有變化則更新。如果一個(gè)值原來是A,變成了B,又變成了A,那么使用cas進(jìn)行檢測(cè)時(shí)會(huì)發(fā)現(xiàn)值沒有發(fā)生變化,其實(shí)是變過的。

    本質(zhì):ABA問題的根本在于cas在修改變量的時(shí)候,無法記錄變量的狀態(tài),比如修改的次數(shù),否修改過這個(gè)變量。這樣就很容易在一個(gè)線程將A修改成B時(shí),另一個(gè)線程又會(huì)把B修改成A,造成cas多次執(zhí)行的問題。

    解決:添加版本號(hào),每次更新的時(shí)候追加版本號(hào),A-B-A一>1A-2B-3A。

    從JDK1.5開始,包提供了一個(gè)類ce來解決ABA的問題。

    CAS循環(huán)時(shí)間長(zhǎng)占用資源大問題

    如果 JVM 能支持處理器提供的pause指令,那么效率會(huì)有一定的提升。

    第一、它可以延遲流水線執(zhí)行指令(de-),使cpu不會(huì)消耗過多的執(zhí)行資源,延遲的時(shí)間取決于具體實(shí)現(xiàn)的版本,有些處理器延遲時(shí)間是0。

    第二、它可以避免在退出循環(huán)的時(shí)候因?yàn)閮?nèi)存順序沖突而引起的CPU流水線被清空,從而提高CPU執(zhí)行效率。

    CAS只能保證一個(gè)共享變量原子操作

    1、對(duì)多個(gè)共享變量操作時(shí),可以用鎖。

    2、可以把多個(gè)共享變量合并成一個(gè)共享變量來操作。比如 x=1,k=a,合并成xk=1a,然后用cas操作xk。

    Tips:java1.5開始,JDK提供了類來保證引用對(duì)象之間的原子性,就可以把多個(gè)變量放在一個(gè)對(duì)象來進(jìn)行cas操作。

    24、關(guān)鍵字

    是輕量級(jí)的,它在多處理器開發(fā)中保證了共享變量的“可見性“。

    Java語言規(guī)范第3版對(duì) 定義如下,Java允許線程訪問共享變量,為了保證共享變量能準(zhǔn)確和一致的更新,線程應(yīng)該確保排它鎖單獨(dú)獲得這個(gè)變量。如果一個(gè)字段被聲明為 ,Java線程內(nèi)存模型所有線程看到這個(gè)變量的值是一致的。

    25、wait

    方法wait()的作用是使當(dāng)前執(zhí)行代碼的線程進(jìn)行等待,wait()是類通用的方法,該方法用來將當(dāng)前線程置入“預(yù)執(zhí)行隊(duì)列”中,并在wait()所在的代碼處停止執(zhí)行,直到接到通知或中斷為止。

    在調(diào)用wait之前,線程需要獲得該對(duì)象的對(duì)象級(jí)別的鎖。代碼體現(xiàn)上,即只能是同步方法或同步代碼塊內(nèi)。調(diào)用wait()后當(dāng)前線程釋放鎖。

    26、

    ()也是類的通用方法,也要在同步方法或同步代碼塊內(nèi)調(diào)用,該方法用來喚醒一個(gè)線程,如果有多個(gè)線程等待,則隨機(jī)挑選出其中一個(gè)處于wait狀態(tài)的線程,對(duì)其發(fā)出通知,并讓它等待獲取該對(duì)象的對(duì)象鎖。

    27、/

    等于說將等待隊(duì)列中的一個(gè)線程移動(dòng)到同步隊(duì)列中,而是將等待隊(duì)列中的所有線程全部移動(dòng)到同步隊(duì)列中。

    28、等待/通知機(jī)制

    一個(gè)線程修改了一個(gè)對(duì)象的值,而另一個(gè)線程感知到了變化,然后進(jìn)行相應(yīng)的操作。

    28.1 等待/通知經(jīng)典范式

    等待wait:

    synchronized(obj) {
    	while(條件不不滿?) {
    		obj.wait();
    	}
    	執(zhí)行對(duì)應(yīng)邏輯
    }
    

    通知:

    synchronized(obj) {
    	改變條件
    	obj.notifyAll();
    }
    

    29、

    主要解決每一個(gè)線程想綁定自己的值,存放線程的私有數(shù)據(jù)。

    29.1 使用

    獲取當(dāng)前的線程的值通過get(),默認(rèn)值為空,設(shè)置set(T)方式來設(shè)置值。

    public class XKThreadLocal {
    	
    	public static ThreadLocal threadLocal = new ThreadLocal();
    	public static void main(String[] args) {
    		if (threadLocal.get() == null) {
    			System.out.println("未設(shè)置過值");
    			threadLocal.set("Java?小咖秀");
    		}
    		System.out.println(threadLocal.get());
    	}
    }
    

    輸出:

    未設(shè)置過值
    Java?小咖秀
    

    29.2 解決get()返回null問題

    通過繼承重寫()方法即可。

    代碼實(shí)現(xiàn):

    public class ThreadLocalExt extends ThreadLocal{
    	
    	static ThreadLocalExt threadLocalExt = new ThreadLocalExt();
    	
    	@Override
    	protected Object initialValue() {
    		return "Java小咖秀";
    	}
    	public static void main(String[] args) {
    		System.out.println(threadLocalExt.get());
    	}
    }
    

    輸出:

    Java小咖秀
    

    30、Lock接口

    鎖可以防止多個(gè)線程同時(shí)共享資源。Java5前,程序是靠實(shí)現(xiàn)鎖功能。Java5之后,并發(fā)包新增Lock接口來實(shí)現(xiàn)鎖功能。

    30.1 Lock接口提供不具備的主要特性 特性描述

    嘗試非阻塞地獲取鎖

    當(dāng)前線程嘗試獲取鎖,如果這一時(shí)刻沒有被其他線程獲取到,則成功獲取并持有鎖

    能被中斷地獲取鎖

    與不同,獲取到鎖的線程能夠響應(yīng)中斷。當(dāng)獲取到鎖的線程被中斷時(shí),中斷異常將會(huì)被拋出,同時(shí)鎖會(huì)被釋放

    超時(shí)獲取鎖

    在指定的截止時(shí)間之前獲取鎖。如果截止時(shí)間到了仍舊無法獲取鎖,則返回。

    30.2 重入鎖

    支持重進(jìn)入的鎖,它表示該鎖能夠支持一個(gè)線程對(duì)資源的重復(fù)加鎖。除此之外,該鎖的還支持獲取鎖時(shí)的公平和非公平性選擇。

    30.3 重進(jìn)入是什么意思?

    重進(jìn)入是指任意線程在獲取到鎖之后能夠再次獲鎖而不被鎖阻塞。

    該特性主要解決以下兩個(gè)問題:

    鎖需要去識(shí)別獲取鎖的線程是否為當(dāng)前占據(jù)鎖的線程,如果是則再次成功獲取。所得鎖最終釋放。線程重復(fù)n次是獲取了鎖,隨后在第n次釋放該鎖后,其他線程能夠獲取到該鎖。 30.4 默認(rèn)鎖?

    默認(rèn)非公平鎖。

    代碼為證:

    final boolean nonfairTryAcquire(int acquires) {
    	final Thread current = Thread.currentThread();
    	int c = getState();
    	if (c == 0) {
    		if (compareAndSetState(0, acquires)) {
    			setExclusiveOwnerThread(current);
    			return true;
    		}
    	} else if (current == getExclusiveOwnerThread()) {
    			int nextc = c + acquires;
    			if (nextc < 0) // overflow
    				throw new Error("Maximum lock count exceeded");
    			setState(nextc);
    			return true;
    	}
    	return false;
    }
    

    31、公平鎖和非公平鎖的區(qū)別

    公平性與否是針對(duì)獲取鎖來說的,如果一個(gè)鎖是公平的,那么鎖的獲取順序就應(yīng)該符合請(qǐng)求的絕對(duì)時(shí)間順序,也就是FIFO。

    32、讀寫鎖

    讀寫鎖允許同一時(shí)刻多個(gè)讀線程訪問,但是寫線程和其他寫線程均被阻塞。讀寫鎖維護(hù)一個(gè)讀鎖一個(gè)寫鎖,讀寫分離,并發(fā)性得到了提升。

    Java中提供讀寫鎖的實(shí)現(xiàn)類是ck。

    33、工具

    定義了一組公共靜態(tài)方法,提供了最基本的線程阻塞和喚醒功能。

    方法名稱描述

    void park()

    阻塞當(dāng)前線程,如果用 ( )方法或者當(dāng)前線程被中斷,才能從park()方法返回

    void (long nanos)

    阻塞當(dāng)前線程,最長(zhǎng)不超過 nanos 納秒,返回條件在 park()的基礎(chǔ)上增加了超時(shí)返回

    void (long )

    阻當(dāng)前線程.直到時(shí)間(從1970年開始到時(shí)間的毫秒數(shù))

    void ( )

    喚醒處于阻塞狀態(tài)的線程

    34、接口

    提供了類似監(jiān)視器方法,與Lock配合使用實(shí)現(xiàn)等待/通知模式。

    34.1 使用

    代碼示例:

    public class XKCondition {
    	Lock lock = new ReentrantLock();
    	Condition cd = lock.newCondition();
    	public void await() throws InterruptedException {
    		lock.lock();
    		try {
    			cd.await();//相當(dāng)于Object 方法中的wait()
    		} finally {
    			lock.unlock();
    		}
    	}
    	public void signal() {
    		lock.lock();
    		try {
    			cd.signal(); //相當(dāng)于Object 方法中的notify()
    		} finally {
    			lock.unlock();
    		}
    	}
    }
    

    35、Java并發(fā)容器 并發(fā)容器描述

    并發(fā)安全版,Java7中采用分段鎖技術(shù)來提高并發(fā)效率,默認(rèn)分16段。Java8放棄了分段鎖,采用CAS,同時(shí)當(dāng)哈希沖突時(shí),當(dāng)鏈表的長(zhǎng)度到8時(shí),會(huì)轉(zhuǎn)化成紅黑樹。

    e

    基于鏈接節(jié)點(diǎn)的無界線程安全隊(duì)列,它采用先進(jìn)先出的規(guī)則對(duì)節(jié)點(diǎn)進(jìn)行排序,當(dāng)我們添加一個(gè)元素的時(shí)候,它會(huì)添加到隊(duì)列的尾部,當(dāng)我們獲取一個(gè)元素時(shí),它會(huì)返回隊(duì)列頭部的元素。它采用cas算法來實(shí)現(xiàn)。

    e

    p

    t

    -------------------------------

    ---------------------------------------------------------------------------

    一個(gè)由數(shù)據(jù)支持的有界阻塞隊(duì)列,此隊(duì)列按照FIFO原則對(duì)元素進(jìn)行排序。隊(duì)列頭部在隊(duì)列中存在的時(shí)間最長(zhǎng),隊(duì)列尾部存在時(shí)間最短。

    雙向隊(duì)列

    e

    一個(gè)支持優(yōu)先級(jí)排序的無界阻塞隊(duì)列,但它不會(huì)阻塞數(shù)據(jù)生產(chǎn)者,而只會(huì)在沒有可消費(fèi)的數(shù)據(jù)時(shí),阻塞數(shù)據(jù)的消費(fèi)者。

    -----------------------

    --------------------------------------------------------------------------

    是一個(gè)支持延時(shí)獲取元素的使用優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)的無界阻塞隊(duì)列。隊(duì)列中的元素必須實(shí)現(xiàn) 接口和 接口,在創(chuàng)建元素時(shí)可以指定多久才能從隊(duì)列中獲取當(dāng)前元素。

    36、阻塞隊(duì)列 36.1 什么是阻塞隊(duì)列?

    隊(duì)列比較好理解,數(shù)據(jù)結(jié)構(gòu)中我們都接觸過,先進(jìn)先出的一種數(shù)據(jù)結(jié)構(gòu),那什么是阻塞隊(duì)列呢?從名字可以看出阻塞隊(duì)列其實(shí)也就是隊(duì)列的一種特殊情況。它具有如下特點(diǎn):

    當(dāng)阻塞隊(duì)列滿了,往隊(duì)列添加元素的操作將會(huì)被阻塞。當(dāng)阻塞隊(duì)列為空時(shí),從隊(duì)列中獲取元素的操作將會(huì)被阻塞。 36.2 阻塞隊(duì)列常用的應(yīng)用場(chǎng)景?

    常用于生產(chǎn)者和消費(fèi)者場(chǎng)景,生產(chǎn)者是往隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里取元素的線程。阻塞隊(duì)列正好是生產(chǎn)者存放、消費(fèi)者來獲取的容器。

    36.3 Java里的阻塞的隊(duì)列 隊(duì)列描述

    數(shù)組結(jié)構(gòu)組成的 、有界阻塞隊(duì)列

    鏈表結(jié)構(gòu)組成的 、有界阻塞隊(duì)列

    e

    支持優(yōu)先級(jí)排序 、無界阻塞隊(duì)列

    優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn) 、無界阻塞隊(duì)列

    不存儲(chǔ)元素 、阻塞隊(duì)列

    鏈表結(jié)構(gòu)組成、無界阻塞隊(duì)列

    鏈表結(jié)構(gòu)組成、雙向阻塞隊(duì)列

    37、Fork/Join

    Java7 提供的一個(gè)用于并行執(zhí)行任務(wù)的框架,把一個(gè)大任務(wù)分割成若干個(gè)小任務(wù),最終匯總每個(gè)小任務(wù)的結(jié)果后得到大任務(wù)結(jié)果的框架。

    37.1 工作竊取算法

    是指某個(gè)線程從其他隊(duì)列里竊取任務(wù)來執(zhí)行。當(dāng)大任務(wù)被分割成小任務(wù)時(shí),有的線程可能提前完成任務(wù),此時(shí)閑著不如去幫其他沒完成工作線程。此時(shí)可以去其他隊(duì)列竊取任務(wù),為了減少競(jìng)爭(zhēng),通常使用雙端隊(duì)列,被竊取的線程從頭部拿,竊取的線程從尾部拿任務(wù)執(zhí)行。

    37.2 工作竊取算法的優(yōu)缺點(diǎn) 38、包

    Java從JDK1.5開始提供了java.util..包,方便程序員在多線程環(huán)境下,無鎖地進(jìn)行原子操作。原子變量的底層使用了處理器提供的原子指令,但是不同的CPU架構(gòu)可能提供的原子指令不一樣,也有可能需要某種形式的內(nèi)部鎖,所以該方法不能絕對(duì)保證線程不被阻塞。

    在包里一共有12個(gè)類,四種原子更新方式,分別是原子更新基本類型,原子更新數(shù)組,原子更新引用和原子更新字段。包里的類基本都是使用實(shí)現(xiàn)的包裝類。

    類原子更新對(duì)象

    原子操作更新基本類型

    布爾類型

    整型類型

    長(zhǎng)整型類型

    原子操作更新數(shù)組

    整型數(shù)組里的元素

    長(zhǎng)整型數(shù)組里的元素

    引用類型數(shù)組里的元素

    原子操作更新引用類型

    引用類型

    引用類型里的字段

    nce

    原子更新帶有標(biāo)記位的引用類型,標(biāo)記位用類型表示,構(gòu)造方法為`nce(V , )`

    原子操作更新字段類

    整型字段的更新器

    ter

    長(zhǎng)整型字段的更新器

    pdate

    帶有版本號(hào)的引用類型 `

    39、JDK并發(fā)包中提供了哪幾個(gè)比較常見的處理并發(fā)的工具類?

    提供并發(fā)控制手段:、、

    線程間數(shù)據(jù)交換:

    39.1

    這個(gè)類 使一個(gè)線程等待其他線程各自執(zhí)行完畢后再執(zhí)行。 是通過一個(gè)計(jì)數(shù)器來實(shí)現(xiàn)的,計(jì)數(shù)器的初始值是線程的數(shù)量。每當(dāng)一個(gè)線程執(zhí)行完畢后,計(jì)數(shù)器的值就-1,當(dāng)計(jì)數(shù)器的值為0時(shí),表示所有線程都執(zhí)行完畢,然后在閉鎖上等待的線程就可以恢復(fù)工作了。

    的構(gòu)造函數(shù)接受一個(gè)int類型的參數(shù)作為計(jì)數(shù)器,你想等待n個(gè)線程完成,就傳入n。

    三個(gè)重要的方法:

    //調(diào)用await()方法的線程會(huì)被掛起,它會(huì)等待直到count值為0才繼續(xù)執(zhí)行
    public void await() throws InterruptedException { };   
    //和await()類似,只不過等待一定的時(shí)間后count值還沒變?yōu)?的話就會(huì)繼續(xù)執(zhí)行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
    //將count值減1
    public void countDown() { };  
    

    Tips:

    39.2

    可循環(huán)使用的屏障。它的作用就是會(huì)讓所有線程都等待完成后才會(huì)繼續(xù)下一步行動(dòng)。 讓一組線程到達(dá)一個(gè)屏障(也可以叫同步點(diǎn))時(shí)被阻塞word沒有響應(yīng)保存 等待,直到最后一個(gè)線程到達(dá)屏障時(shí),屏障才會(huì)開門,所有被屏障攔截的線程才會(huì)繼續(xù)運(yùn)行。

    舉個(gè)例子,就像生活中我們會(huì)約朋友們到某個(gè)餐廳一起吃飯,有些朋友可能會(huì)早到,有些朋友可能會(huì)晚到,但是這個(gè)餐廳規(guī)定必須等到所有人到齊之后才會(huì)讓我們進(jìn)去。這里的朋友們就是各個(gè)線程,餐廳就是 。

    默認(rèn)構(gòu)造器是(int ),其參數(shù)表示屏障攔截的線程數(shù)量,每個(gè)線程調(diào)用await方法告訴我已經(jīng)到達(dá)屏障,然后當(dāng)前線程被阻塞。

    39.3 與區(qū)別 計(jì)數(shù)器等待

    計(jì)數(shù)器只能使用一次

    一個(gè)線程或多個(gè)等待另外n個(gè)線程完成之后才能執(zhí)行

    計(jì)數(shù)器可以重置(通過reset()方法)

    n個(gè)線程相互等待,任何一個(gè)線程完成之前,所有的線程都必須等待。

    39.4

    用來控制同時(shí)訪問資源的線程數(shù)量,通過協(xié)調(diào)各個(gè)線程,來保證合理的公共資源的訪問。

    應(yīng)用場(chǎng)景:流量控制,特別是公共資源有限的應(yīng)用場(chǎng)景,比如數(shù)據(jù)鏈接,限流等。

    39.5

    是一個(gè)用于線程間協(xié)作的工具類,它提供一個(gè)同步點(diǎn),在這個(gè)同步點(diǎn)上,兩個(gè)線程可以交換彼此的數(shù)據(jù)。比如第一個(gè)線程執(zhí)行()方法,它會(huì)一直等待第二個(gè)線程也執(zhí)行(),當(dāng)兩個(gè)線程都到同步點(diǎn),就可以交換數(shù)據(jù)了。

    一般來說為了避免一直等待的情況,可以使用(V x,long , unit),設(shè)置最大等待時(shí)間。

    可以用于遺傳算法。

    40、線程池 40.1 為什么使用線程池

    幾乎所有需要異步或者并發(fā)執(zhí)行任務(wù)的程序都可以使用線程池。合理使用會(huì)給我們帶來以下好處:

    40.2 線程池工作流程

    假設(shè)線程池的最大容量為5個(gè),其中核心線程池容量為3個(gè),非核心線程池容量為2個(gè)。工作隊(duì)列的容量大小為2個(gè)。

    一開始,線程池里的線程個(gè)數(shù)為0,這時(shí)候任務(wù)1來了,線程池管理者就會(huì)創(chuàng)建1個(gè)線程,用來執(zhí)行任務(wù)1,接著任務(wù)2、3也來了,線程池管理者就會(huì)再創(chuàng)建兩個(gè)線程,用來執(zhí)行任務(wù)2和3。此時(shí),線程池里一共3個(gè)線程,也就是核心線程池滿了。

    這時(shí)候,又來一個(gè)任務(wù)4,但是核心線程池已經(jīng)滿了,管理者就會(huì)讓它到工作隊(duì)列進(jìn)行排隊(duì),任務(wù)5來了,同樣也是在工作隊(duì)列里等待。此時(shí),等待隊(duì)列已滿。

    這時(shí)候任務(wù)1執(zhí)行完了,釋放了一個(gè)線程1,就可以讓任務(wù)4出隊(duì)被處理。然后,任務(wù)6和7來了。此時(shí),三個(gè)核心線程都在工作,工作隊(duì)列還有一個(gè)空位。任務(wù)6去了工作隊(duì)列排隊(duì),任務(wù)7沒有位置坐。因?yàn)榫€程池最大可以放5個(gè)線程,只有核心線程池3個(gè)滿了,還有兩個(gè)位置可以放非核心線程,所以管理者會(huì)創(chuàng)建一個(gè)非核心線程,然后任務(wù)5出隊(duì),任務(wù)7入隊(duì)。

    直到線程池全滿(5個(gè)),工作隊(duì)列也滿,新來的任務(wù)才會(huì)無法被處理。優(yōu)先使用線程池中的核心線程池。

    40.3 創(chuàng)建線程池參數(shù)有哪些作用?

    public ThreadPoolExecutor(   int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler)
    

    :設(shè)置創(chuàng)建線程的工廠,可以通過線程工廠給每個(gè)創(chuàng)建出來的線程設(shè)置更有意義的名字。:飽和策略也叫拒絕策略。當(dāng)隊(duì)列和線程池都滿了,即達(dá)到飽和狀態(tài)。所以需要采取策略來處理新的任務(wù)。默認(rèn)策略是。 40.4 向線程池提交任務(wù)

    可以使用()和()兩種方式提交任務(wù)。

    40.5 關(guān)閉線程池

    可以通過()或()來關(guān)閉線程池。它們的原理是遍歷線程池中的工作線程,然后逐個(gè)調(diào)用線程的來中斷線程,所以無法響應(yīng)終端的任務(wù)可以能永遠(yuǎn)無法停止。

    首先將線程池狀態(tài)設(shè)置成STOP,然后嘗試停止所有的正在執(zhí)行或者暫停的線程,并返回等待執(zhí)行任務(wù)的列表。

    只是將線程池的狀態(tài)設(shè)置成狀態(tài),然后中斷所有沒有正在執(zhí)行任務(wù)的線程。

    只要調(diào)用兩者之一,就會(huì)返回true,當(dāng)所有任務(wù)都已關(guān)閉,就會(huì)返回true。

    一般來說調(diào)用方法來關(guān)閉線程池,如果任務(wù)不一定要執(zhí)行完,可以直接調(diào)用方法。

    40.6 線程池如何合理設(shè)置

    配置線程池可以從以下幾個(gè)方面考慮。

    任務(wù)優(yōu)先級(jí),高中低。任務(wù)時(shí)間執(zhí)行長(zhǎng)短。任務(wù)依賴性:是否依賴其他系統(tǒng)資源。

    可以通過.().()來獲取cpu個(gè)數(shù)。建議使用有界隊(duì)列,增加系統(tǒng)的預(yù)警能力和穩(wěn)定性。

    41、

    從JDK5開始,把工作單元和執(zhí)行機(jī)制分開。工作單元包括和,而執(zhí)行機(jī)制由框架提供。

    41.1 框架的主要成員 :可以通過工廠類來創(chuàng)建。有2種類型: 接口:和實(shí)現(xiàn)接口的類來表示異步計(jì)算的結(jié)果。和:它們的接口實(shí)現(xiàn)類都可以被或執(zhí)行。不能返回結(jié)果,可以返回結(jié)果。 41.2

    查看源碼:

    public static ExecutorService newFixedThreadPool(int nThreads) {
       return new ThreadPoolExecutor(nThreads, nThreads,
                                     0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>());}
    

    1、特點(diǎn)

    2、使用無界隊(duì)列的影響

    3、 處理流程

    4、適用場(chǎng)景

    適用于為了滿足資源管理的需求,而需要限制當(dāng)前線程數(shù)量的應(yīng)用場(chǎng)景,它適用于負(fù)載比較重的服務(wù)器。

    41.3

    查看源碼:

    public static ExecutorService newSingleThreadExecutor() {
    	return new FinalizableDelegatedExecutorService
    		(new ThreadPoolExecutor(1, 1,
    								0L, TimeUnit.MILLISECONDS,
    								new LinkedBlockingQueue<Runnable>()));
    }
    

    1、特點(diǎn)

    2、適用場(chǎng)景

    適用于需要保證順序地執(zhí)行各個(gè)任務(wù),并且在任意時(shí)間點(diǎn),不會(huì)有多個(gè)線程是活動(dòng)的應(yīng)用場(chǎng)景。

    3、工作流程

    執(zhí)行流程以及造成的影響同。

    41.4

    查看源碼:

    public static ExecutorService newCachedThreadPool() {
    	return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
    									60L, TimeUnit.SECONDS,
    									new SynchronousQueue<Runnable>());
    

    1、特點(diǎn)

    2、工作流程

    3、 適用場(chǎng)景

    是無界的線程池,適用于執(zhí)行很多的短期異步任務(wù)的小程序,或者是負(fù)載較輕的服務(wù)器。

網(wǎng)站首頁(yè)   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號(hào):冀ICP備2024067069號(hào)-3 北京科技有限公司版權(quán)所有