国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站 建設(shè)網(wǎng)站市場調(diào)研分析

網(wǎng)站 建設(shè)網(wǎng)站,市場調(diào)研分析,商洛做網(wǎng)站多少錢,網(wǎng)站建設(shè)預(yù)算鞏固基礎(chǔ),砥礪前行 。 只有不斷重復(fù),才能做到超越自己。 能堅持把簡單的事情做到極致,也是不容易的。 如何理解volatile關(guān)鍵字 在并發(fā)領(lǐng)域中,存在三大特性:原子性、有序性、可見性。volatile關(guān)鍵字用來修飾對象的屬性…

鞏固基礎(chǔ),砥礪前行 。
只有不斷重復(fù),才能做到超越自己。
能堅持把簡單的事情做到極致,也是不容易的。

如何理解volatile關(guān)鍵字

在并發(fā)領(lǐng)域中,存在三大特性:原子性、有序性、可見性。volatile關(guān)鍵字用來修飾對象的屬性,在并發(fā)環(huán)境下可以保證這個屬性的可見性,對于加了volatile關(guān)鍵字的屬性,在對這個屬性進行修改時,會直接將CPU高級緩存中的數(shù)據(jù)寫回到主內(nèi)存,對這個變量的讀取也會直接從主內(nèi)存中讀取,從而保證了可見性,底層是通過操作系統(tǒng)的內(nèi)存屏障來實現(xiàn)的,由于使用了內(nèi)存屏障,所以會禁止指令重排,所以同時也就保證了有序性,在很多并發(fā)場景下,如果用好volatile關(guān)鍵字可以很好的提高執(zhí)行效率。

ReentrantLock中的公平鎖和非公平鎖的底層實現(xiàn)

首先不管是公平鎖和非公平鎖,它們的底層實現(xiàn)都會使用AQS來進行排隊,它們的區(qū)別在于:線程在使用lock()方法加鎖時,如果是公平鎖,會先檢查AQS隊列中是否存在線程在排
隊,如果有線程在排隊,則當(dāng)前線程也進行排隊,如果是非公平鎖,則不會去檢查是否有線程在排隊,而是直接競爭鎖。
不管是公平鎖還是非公平鎖,一旦沒競爭到鎖,都會進行排隊,當(dāng)鎖釋放時,都是喚醒排在最前面的線程,所以非公平鎖只是體現(xiàn)在了線程加鎖階段,而沒有體現(xiàn)在線程被喚醒階
段。
另外,ReentrantLock是可重入鎖,不管是公平鎖還是非公平鎖都是可重入的。

Sychronized的偏向鎖、輕量級鎖、重量級鎖

1.偏向鎖:在鎖對象的對象頭中記錄一下當(dāng)前獲取到該鎖的線程ID,該線程下次如果又來獲取該鎖就可以直接獲取到了
2.輕量級鎖:由偏向鎖升級而來,當(dāng)一個線程獲取到鎖后,此時這把鎖是偏向鎖,此時如果有第二個線程來競爭鎖,偏向鎖就會升級為輕量級鎖,
之所以叫輕量級鎖,是為了和重量級鎖區(qū)分開來,輕量級鎖底層是通過自旋來實現(xiàn)的,并不會阻塞線程
3.如果自旋次數(shù)過多仍然沒有獲取到鎖,則會升級為重量級鎖,重量級鎖會導(dǎo)致線程阻塞
4.自旋鎖:自旋鎖就是線程在獲取鎖的過程中,不會去阻塞線程,也就無所謂喚醒線程,阻塞和喚醒這兩個步驟都是需要操作系統(tǒng)去進行的,比較消耗時間,自旋鎖是線程通過CAS獲取預(yù)期的一個標(biāo)記,如果沒有獲取到,則繼續(xù)循環(huán)獲取,如果獲取到了則表示獲取到了鎖,這個過程線程一直在運行中,相對而言沒有使用太多的操作系統(tǒng)資源,比較輕量。

Sychronized和ReentrantLock的區(qū)別

  1. sychronized是一個關(guān)鍵字,ReentrantLock是一個類
    2.sychronized會自動的加鎖與釋放鎖,ReentrantLock需要程序員手動加鎖與釋放鎖
    3.sychronized的底層是JVM層面的鎖,ReentrantLock是API層面的鎖
    4.sychronized是非公平鎖,ReentrantLock可以選擇公平鎖或非公平鎖
    5.sychronized鎖的是對象,鎖信息保存在對象頭中,ReentrantLock通過代碼中int類型的state標(biāo)識來標(biāo)識鎖的狀態(tài)
    6.sychronized底層有一個鎖升級的過程

線程池的底層工作原理

線程池內(nèi)部是通過隊列+線程實現(xiàn)的,當(dāng)我們利用線程池執(zhí)行任務(wù)時:
1.如果此時線程池中的線程數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài),也要創(chuàng)建新的線程來處理被添加的任務(wù)。
2.如果此時線程池中的線程數(shù)量等于corePoolSize,但是緩沖隊列workQueue未滿,那么任務(wù)被放入緩沖隊列。
3.如果此時線程池中的線程數(shù)量大于等于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數(shù)量小于maximumPoolsize,建新的線程來處理被添加的任務(wù)。
4.如果此時線程池中的線程數(shù)量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數(shù)量等于maximumPoolSize,那么通過 handler所指
定的策略來處理此任務(wù)。
5.當(dāng)線程池中的線程數(shù)量大于corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態(tài)的調(diào)整池中的線
程數(shù)

死鎖編碼和定位分析

package ttzz.juc.juc2;
/*** 第55講  死鎖編碼和定位分析* 1.什么是死鎖?*  指兩個或者兩個以上的進程在執(zhí)行過程中,因爭奪資源而造成的互相等待的現(xiàn)象,若無外力干預(yù),他們將持續(xù)性的耗下去,*  如果系統(tǒng)資源充足,進程的資源請求都能得到滿足,死鎖出現(xiàn)的可能性低,否則就會因為爭奪有限的資源而陷入死鎖*  2. 造成死鎖的原因:*   1)系統(tǒng)資源不足*   2)代碼問題*   3)內(nèi)存分配不合理*/
public class ThreadPool_55 {public static void main(String[] args) {String lockA = "lockA";String lockB = "lockB";new Thread(new LockThread(lockA,lockB),"ThreadAAA").start();new Thread(new LockThread(lockB,lockA),"ThreadBBB").start();/*** 查看進程* linux  ps -ef|grep XXX  ;ls -l* windows :jps -l  找到進程編號 ;jstack pid*/}
}
class LockThread implements Runnable{private String lockA;private String lockB;public LockThread(String lockA, String lockB) {super();this.lockA = lockA;this.lockB = lockB;}@Overridepublic void run() {synchronized (lockA) {System.out.println(Thread.currentThread().getName()+":占有鎖:"+lockA+",嘗試獲得鎖"+lockB);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockB) {System.out.println(Thread.currentThread().getName()+":占有鎖:"+lockB+",嘗試獲得鎖"+lockA);}}}}

Java 線程池


/*** 為啥使用線程池?線程池的優(yōu)勢是什么 ? 第46講* 降低資源消耗:通過重復(fù)利用已經(jīng)創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗;提高響應(yīng)速度:當(dāng)任務(wù)到達時,任務(wù)可以不需要等到線程創(chuàng)建就能執(zhí)行;提高線程的可管理性:線程是稀缺資源,不能無限創(chuàng)建,否則會消耗系統(tǒng)資源、降低系統(tǒng)的穩(wěn)定性,使用線程可以進行統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控;* 線程池的三種常用方式?(一共有5中)   第47講* 常用的三種:* 	Executors.newFixedThreadPool(nThreads)* 			使用場景:執(zhí)行長期任務(wù),性能較好* 			源碼:   public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}Executors.newSingleThreadExecutor()使用場景:單任務(wù)執(zhí)行源碼:    public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}Executors.newCachedThreadPool()使用場景:執(zhí)行短期異步小程序或者負(fù)載較輕的服務(wù)器源碼:   public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}* 剩下的兩種:* Executors.newScheduleThreadPool() 帶有時間調(diào)度的線程池* Java8中推出的 Executors.newWorkStealingPool(int) 使用目前機器上可用的處理器作為它的并行級別* * * 第48講(線程池7個參數(shù)簡介) * ThreadPoolExecutor:底層實現(xiàn)  * 線程池幾個重要參數(shù)介紹:*     public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);}第49講(線程池7個參數(shù)深入介紹) 類比于銀行網(wǎng)點辦理業(yè)務(wù)corePoolSize:線程池中常駐核心線程池maximumPoolSize:線程池中能夠容納同時執(zhí)行最大線程數(shù),該值必須大于等于1keepAliveTime:多余線程的最大存活時間unit:keepAliveTime的單位workQueue:任務(wù)隊列,被提交但尚未被執(zhí)行的任務(wù)threadFactory:生成線程池中工作線程的線程工廠,一般使用默認(rèn)即可handler:拒絕策略,表示當(dāng)任務(wù)隊列滿并且工作線程大于等于線程池的最大線程數(shù)時,對即將到來的線程的拒絕策略第50講(線程池底層工作原理)線程池具體工作流程:在創(chuàng)建線程后,等待提交過來的任務(wù)請求當(dāng)調(diào)用execute()/submit()方法添加一個請求任務(wù)時,線程池會做出以下判斷:如果正在運行的線程數(shù)量小于corePoolSize,會立刻創(chuàng)建線程運行該任務(wù)如果正在運行的線程數(shù)量大于等于corePoolSize,會將該任務(wù)放入阻塞隊列中如果隊列也滿但是正在運行的線程數(shù)量小于maximumPoolSize,線程池會進行拓展,將線程池中的線程數(shù)拓展到最大線程數(shù)(并立即運行)如果隊列滿并且運行的線程數(shù)量大于等于maximumPoolSize,那么線程池會啟動相應(yīng)的拒絕策略來拒絕相應(yīng)的任務(wù)請求當(dāng)一個線程完成任務(wù)時,它會從隊列中取下一個任務(wù)來執(zhí)行當(dāng)一個線程空閑時間超過給定的keepAliveTime時,線程會做出判斷:如果當(dāng)前運行線程大于corePoolSize,那么該線程將會被停止。也就是說,當(dāng)線程池的所有任務(wù)都完成之后,它會收縮到corePoolSize的大小**/
package ttzz.juc.juc2;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPool_46_47_48_49_50 {public static void main(String[] args) {//測試線程池中的線程數(shù)達到核心線程,并且阻塞隊列中也滿了,//但是未達到最大線程數(shù)時的邏輯處理ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 100L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3));try {for (int i = 1; i <= 6; i++) {final int num = i;threadPoolExecutor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+":"+num);try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}}});}} finally {threadPoolExecutor.shutdown();}}/*** 測試各種線程池*/public static void testThreadPool() {
//		ExecutorService executorService = Executors.newFixedThreadPool(5);ExecutorService executorService = Executors.newSingleThreadExecutor();
//		ExecutorService executorService = Executors.newCachedThreadPool();try {for (int i = 0; i < 10; i++) {executorService.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"處理業(yè)務(wù)");}});}} catch (Exception e) {}finally {executorService.shutdown();}}
}
/*** 第51講(線程池的四種拒絕策略理論介紹)* * 線程池的拒絕策略 第51講(線程池的四種拒絕策略理論介紹)* 1. 什么是線程池的拒絕策略?* 		等待隊列滿了,再也容不下新的任務(wù),同時線程池達到了最大線程,無法繼續(xù)為新任務(wù)服務(wù)了。* 		這個時候,就需要使用拒絕策略機制合理的處理這個問題* 2. jdk內(nèi)置的四種拒絕策略 RejectedExecutionHandler* 		AbortPolicy(默認(rèn)):直接拋出RejectedExecutionException 異常 阻止系統(tǒng)正常運行* 		CallerRunsPolicy:調(diào)用者運行的一種機制,該策略既不會拋棄任務(wù),也不會拋出異常,* 						而是將某些任務(wù)回退到調(diào)用者DiscardOldestPolicy:拋棄隊列中等待最久的任務(wù),然后把當(dāng)前任務(wù)加入到隊列中嘗試再次提交當(dāng)前任務(wù)DiscardPolicy:直接丟棄任務(wù),不予任何處理也不拋出異常。如果任務(wù)允許丟失,那么該策略是最好的方案第52講(線程池實際中使用那種線程池??)					* 3. 線程池實際中使用那種線程池?* 		一個都不用,生產(chǎn)上只用我們自定義的線程池* 		jdk已經(jīng)提供了現(xiàn)成的,你為啥不用呢 ?* 			并發(fā)處理阿里巴巴手冊中有說明* 4. 并發(fā)處理阿里巴巴手冊* 		1)獲取單例對象需要保證線程安全,其中的方法也要保證線程安全* 				資源驅(qū)動類,工具類、單例工廠都許需要注意* 		2)創(chuàng)建線程或者線程池時指定有意義的線程的名稱,方便出錯排查* 		3)線程資源必須通過線程池提供,不允許在應(yīng)用中自行顯示的創(chuàng)建線程* 			使用線程池的好處是減少在創(chuàng)建和銷毀線程上的時間以及系統(tǒng)資源的開銷,解決資源不足的問題* 			如果不適用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者 過度切換的問題* 		4)線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor的方式,這樣處理方式讓* 			寫的同學(xué)更加名且線程池的運行規(guī)則,規(guī)避資源耗盡的風(fēng)險* 			Executors返回的線程池對象弊端如下:* 			FixedThreadPool和SingleThreadExecutor 允許的請求隊列長度最大時Integer.maxValue,可能會堆積大量請求導(dǎo)致oom* 			CachedThreadPool和ScheduleThreadPool 允許的請求隊列長度最大時Integer.maxValue,可能創(chuàng)建大量線程導(dǎo)致oom* 第53講(線程池的手寫改造和拒絕策略)* 				 * 第54講(線程池配置合理線程)*     合理配置線程池,你是如何考慮的?*     按照業(yè)務(wù)分為兩種,其次要熟悉自己的硬件配置或者服務(wù)器配置,*     1)CPU密集型*     			//獲取cpu的核心數(shù)System.out.println(Runtime.getRuntime().availableProcessors());CPU密集型 的意思時給業(yè)務(wù)需要大量的運算,而沒有阻塞,cpu一致全速運行cpu密集任務(wù)只有在真正的多喝cpu上才可能得到加速(通過多線程)而在單核cpu上(悲劇),無論你開幾個模擬的多線程該任務(wù)都不可能得到加速,因為cpu中的運算能力就哪些CPU密集型任務(wù)配置盡可能減少線程數(shù)量一般的公式:CPU核心數(shù)+1個線程的線程池*     2)IO密集型* 			 A: 由于IO密集型任務(wù)并不是一直在執(zhí)行任務(wù),則應(yīng)配置盡可能多的線程,入CPU核心數(shù)*2* 			 B: IO密集型,即該任務(wù)需要大量的阻塞,* 				在單線程上運行io密集型的任務(wù)會浪費大量的cpu運算能力,浪費在等待上* 				所以io密集型任務(wù)需要使用多線程可以大大加速線程運行,及時在單核cpu上,這種加速主要是利用了被* 				浪費掉的阻塞時間* 				io密集型是,大部分線程都阻塞,所以需要多配置線程數(shù)* 				參考公式:cpu核心數(shù)/(1-阻塞系數(shù) )阻塞系數(shù)在0.8-0.9之間*              比如8核cpu: 8 / (1-0.9) = 80個核心數(shù)  */
package ttzz.juc.juc2;import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;import org.omg.SendingContext.RunTime;
public class ThreadPool_51_52_53_54 {public static void main(String[] args) {//獲取cpu的核心數(shù)System.out.println(Runtime.getRuntime().availableProcessors());ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,5, 1L,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),
//				new ThreadPoolExecutor.AbortPolicy());
//				new ThreadPoolExecutor.CallerRunsPolicy());new ThreadPoolExecutor.DiscardOldestPolicy());
//				new ThreadPoolExecutor.DiscardPolicy());/***  最大線程數(shù)= 最大線程數(shù)+隊列長度 *  * AbortPolicy:超過 最大線程數(shù) 報異常* 		Exception in thread "main" pool-1-thread-1辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-5辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-1辦理業(yè)務(wù)java.util.concurrent.RejectedExecutionException: Task ttzz.juc.test2.ThreadPool_51$1@55f96302 rejected from java.util.concurrent.ThreadPoolExecutor@3d4eac69[Running, pool size = 5, active threads = 0, queued tasks = 0, completed tasks = 8]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)at ttzz.juc.test2.ThreadPool_51.main(ThreadPool_51.java:79)* CallerRunsPolicy:超過 最大線程數(shù) ,回退給調(diào)用者* 	pool-1-thread-1辦理業(yè)務(wù)main辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-1辦理業(yè)務(wù)pool-1-thread-5辦理業(yè)務(wù)DiscardOldestPolicy:超過 最大線程數(shù) ,拋棄隊列中等待最久的任務(wù),然后把當(dāng)前任務(wù)加入到隊列中嘗試再次提交當(dāng)前任務(wù)	pool-1-thread-1辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-5辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-5辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-1辦理業(yè)務(wù)DiscardPolicy:	超過 最大線程數(shù) ,直接丟棄任務(wù),不予任何處理也不拋出異常。如果任務(wù)允許丟失,那么該策略是最好的方案pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-1辦理業(yè)務(wù)pool-1-thread-3辦理業(yè)務(wù)pool-1-thread-5辦理業(yè)務(wù)pool-1-thread-2辦理業(yè)務(wù)pool-1-thread-4辦理業(yè)務(wù)*/try {// 最大線程數(shù)= 最大線程數(shù)+隊列長度  for (int i = 1; i <=9; i++) {final int num = i;threadPoolExecutor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"辦理業(yè)務(wù)");
//						try {
//							TimeUnit.SECONDS.sleep(4);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}}});}} finally {threadPoolExecutor.shutdown();}}
}

請談?wù)勀銓olatile的理解

volatile 是java提供的輕量級的同步機制
保證可見性
不保證原子性
禁止指令重排(有序性)
指令重排:在計算機執(zhí)行程序時,為了題號新能,編譯器和處理器常常會對指令做重排。一般分為一下三種:
原代碼-》編譯器優(yōu)化的重排-》指令并行的重排-》內(nèi)存系統(tǒng)的重排-》最終執(zhí)行的指令

單線程環(huán)境里面保證程序最終執(zhí)行結(jié)果和代碼順序執(zhí)行結(jié)果一致
處理器在進行重排序時必須考慮指令之間的數(shù)據(jù)依賴性
多線程環(huán)境中線程交替執(zhí)行,優(yōu)于編譯器優(yōu)化重排的存在。兩個線程中使用的
變量能夠保證一致性是無法確定的,結(jié)果無法預(yù)測

volatile 實現(xiàn)禁止指令重排,從而避免多線程環(huán)境下程序出阿信亂序執(zhí)行的現(xiàn)象

先了解一個概念,內(nèi)存屏障,Merray Barries,是一個內(nèi)存指令。他有兩個作用:一個是保證操作的執(zhí)行順序,
另一個是保證某些變量的內(nèi)存可見性(利用該特性實現(xiàn)了volatile的內(nèi)存可見性)。由于編譯器和處理器都能執(zhí)行指令重排
優(yōu)化,如果在指令中插入一條memory barries則會告訴編譯器和cpu,不管什么指令都不能和這條memory barries指令重排。
也就是說通過插入內(nèi)存屏障禁止在內(nèi)存屏障前后的指令執(zhí)行重排序優(yōu)化,內(nèi)存屏障的另一個作用則是強制刷出各種cpu的緩存數(shù)據(jù)。
因此任何cpu上的線程都能讀取到這些數(shù)據(jù)的最新版本。

對volatile變量進行寫操作時,會在操作后加入一條store屏障指令,將工作內(nèi)存中的共享變量值刷新到主內(nèi)存中;
對volatile變量進行寫讀操作時,會在讀操作前加一條load指令,從從主內(nèi)存中讀取共享變量

lock和unlock數(shù)量 對程序代碼的影響

結(jié)論:

當(dāng)lock.lock()數(shù)量 > lock.unlock():程序一直運行
當(dāng)lock.lock()數(shù)量 < lock.unlock():拋出java.lang.IllegalMonitorStateException異常
public class Lock_25 {public static void main(String[] args) {demo11 d = new demo11();for (int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {d.PP();} catch (InterruptedException e) {e.printStackTrace();}}},"生產(chǎn)者").start();new Thread(new Runnable() {@Overridepublic void run() {try {d.CC();} catch (InterruptedException e) {e.printStackTrace();}}},"消費者").start();}}
}class demo11{private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();private Integer num = 0;public void PP() throws InterruptedException {lock.lock();try {while(num!=0) {condition.await();}num++;System.out.println("生產(chǎn)者:"+num);condition.signal();} finally {lock.unlock();}}public void CC() throws InterruptedException {//lock.lock();  少一個程序報錯//lock.lock();  多一個程序一直運行try {while(num==0) {condition.await();}num--;Thread.sleep(200);System.out.println("消費者:"+num);condition.signal();} finally {lock.unlock();}}
}

BlockingQueue 的繼承

public interface BlockingQueue extends Queue
在這里插入圖片描述

線程池的拒絕策略

在這里插入圖片描述

并發(fā)編程–Java中的原子操作類

?
在Java JDK1.5以后,在java.util.concurrent.atomic包,在這個包中提供了一種簡單、新能高效的、線程安全的更新一個變量的方式。

Atomic類中提供了13個類,4中數(shù)據(jù)類型的原子更新方式:原子更新基本類型、原子更新數(shù)組、原子更新引用、原子更新屬性。

原子更新基本類型類
AtomicBoolean、AtomicInteger、AtomicLong ,他們提供的方法基本一樣。

以AtomicInteger為例,提供的API如下:

int addAndGet(int value)將value和原子類中的值相加,返回相加之和的結(jié)果。boolean compareAndSet(int except,int update)int getAndIncrement() 將原子類中的值+1,注意:返回的是自增前的值void lazySet(int value) 有延遲作用int getAndSet(int value)

其中,compareAndSet使用的是unsafe類中的cas,比較并交換。

原子更新數(shù)組
AtomicIntegerArray、AtomicIongArray、AtomicRefrenceArray

int addAndGet(int i,int value)i表示數(shù)組下標(biāo)

boolean compareAndSet(int i,int except,int update)

原子更新引用類型
AtomicRefrence 原子更新引用類型

AtomicRefrenceFieldUpdater 更新引用類型中里的字段

AtomicMakableReference 帶有標(biāo)記的引用類型。

??

原子更新字段類
AtomicIntegerFiledUpdater 更新對象中的Integer類型

AtomicLongFiledUpdater 更新對象中的Long類型

AtomicStampedUpdater 帶有版本號的引用類型,可以有效解決ABA問題。

想要更新字段類需要兩步:1.因為原子更新字段類都是抽象類,妹子使用的時候需要使用靜態(tài)方法newUpdater()構(gòu)建一個更新器,并需要設(shè)置想要更新的類和屬性 2.更新類的屬性必須使用public volatite修飾符。

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;public class TestCase {private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater= AtomicIntegerFieldUpdater.newUpdater(User.class, "age");public static void main(String[] args) {User u  = new User("name1",10);System.out.println(u.getAge());System.out.println(atomicIntegerFieldUpdater.getAndIncrement(u));//getAndIncrement返回的是更新前的數(shù)值System.out.println(atomicIntegerFieldUpdater.get(u));}public static class User{private String name;public volatile int age;public User(String name, int age) {super();this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
}

并發(fā)編程 聊聊ConcurrentHashMap

ConcurrentHashMap 是線程安全 高效的HashMap,聊聊它是如何保證安全的同時實現(xiàn)高效操作的?

為什么使用它?
并發(fā)編程中HashMap可能導(dǎo)致死循環(huán),使用HashTable效率低下,所以就是用ConcurrentHashMap嘍。

死循環(huán)的HashMap

效率底下的HashTable?
HashTable同期使用synchoronized來保證線程安全,但是在線程競爭激烈的請款下HashTable效率低,因為當(dāng)一個線程訪問HashTable的同步方法時,其他線程也訪問HashTable的同步方法時,會進入到阻塞或者輪訓(xùn)狀態(tài)。競爭越激烈效率越低下。

ConcurrentHashMap的鎖分段技術(shù)可以有效的提升并發(fā)訪問效率
HashTable容器在競爭激烈的并發(fā)環(huán)境下表現(xiàn)出來的效率低下的原因是所有訪問HashTable的線程都必須競爭同一把鎖,加入容器中有多把鎖,每一把鎖用于鎖容器中的一部分?jǐn)?shù)據(jù),那么當(dāng)多線程訪問容器里不同的數(shù)據(jù)時,線程間就不存在鎖競爭。從而有效提高線程并發(fā)訪問效率,這就是ConcurrentHashMap所使用的的鎖分段技術(shù)。首先將數(shù)據(jù)分成一段一段地存儲,然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個線程占用鎖訪問其中的一段數(shù)據(jù)時,其他段的數(shù)據(jù)也可能被其他線程訪問。

ConcurrentHashMap的結(jié)構(gòu)
ConcurrentHashMap是有segment數(shù)組和HashEntry數(shù)組結(jié)構(gòu)構(gòu)成的,segment是一種可重入鎖(ReentrantLock),在ConcurrentHashMap中扮演鎖的角色;HashEntry則是用于存儲鍵值對數(shù)據(jù),一個ConcurrentHashMap里包含一個segment數(shù)組。segment數(shù)組的結(jié)構(gòu)和hashmap類似,是一種數(shù)組和鏈表結(jié)構(gòu)。一個segment里包含一個HashEntry數(shù)組,每個HashEntry是一個鏈表結(jié)構(gòu)的元素,每個segment守護著一個HashEntry數(shù)組里的元素,當(dāng)對HashEntry數(shù)組的元素修改時,必須首先獲得segment鎖。

ConcurrentHashMap的初始化
ConcurrentHashMap初始化方法時通過initCapacity、loadFactory、concurrencyLevel等幾個參數(shù)來初始化segment數(shù)組、偏移量segmentShift、段掩碼segmentMask和每個segment里的HashEntry數(shù)組來實現(xiàn)。

ConcurrentHashMap的操作
get 、 put、size

get操作:get操作簡單高效。先經(jīng)過一次散列,然后在使用得到的散列值 通過散列 定位到segment,在通過散列算法定位到元素。

get操作高效 在于整個過程中不許要加鎖,除非讀到的值是空才會加鎖重讀。ConcurrentHashMap的get方法為啥不加鎖?她的get方法里需要使用共享變量多需要定義成volatile類型,用于作用當(dāng)前segment大小的count字段和使用存儲值得hashentry的value。定義成為valatile的變量,能夠在各個線程之間保持可見性,能被多線程同事督導(dǎo),并且保證不會讀取到過期值,但是只能被單線程寫(一種特殊的情況可以被多線程寫,就是寫入的值不依賴于原值),在get操作里只需要讀不需要寫共享變量count和value。所以不需要加鎖。之所以不會不會讀到過期的數(shù)據(jù),是因為java內(nèi)存模型中的happen berfre原則,對volatile字段的寫入操作先于讀取操作。

put操作:put方法需要對共享變量進行寫入操作,所以為了線程安全,在操作共享變量時需要加鎖。put方法首先定位到segment,然后在segment數(shù)組進行insert操作,insert操作需要經(jīng)過兩個步驟,第一需要對segment素組里的hashentry數(shù)組做判斷,是否需要擴容,第二定位添加元素的位置,讓后insert到hashentry數(shù)組中。

判斷是否需要擴容,segment里的hashentry數(shù)組是否超過容量,如果超過,則擴容。hashmap的擴容方式是先insert,然后在判斷。

如何擴容:首先創(chuàng)建一個容量是當(dāng)前容量的2倍的數(shù)組,然后將原來數(shù)組里的元素進行散列后insert到新數(shù)組中。為了高效,ConcurrentHashMap不會對所有的segment數(shù)組驚喜擴容,僅僅對segment進行擴容。

size操作:統(tǒng)計ConcurrentHashMap里的元素的。統(tǒng)計每個segment中的count值,相加,這種方式存在一個問題,就是在計算的時候,獲取的count不是最新值,有可能在計算時有可能對數(shù)組的元素進行操作。就會導(dǎo)致統(tǒng)計不準(zhǔn)。最安全的方法就是在統(tǒng)計的時候,對所有segment的操作進行鎖住。但是這種方式低效。它是如何做的呢?它是使用先累加,然后再判斷的方式。在累加count操作過程中,之間累加過得count變化幾率小,所以ConcurrentHashMap的做法就是先嘗試2次通過不給segment加鎖的方式來統(tǒng)計各個segment的大小。如果統(tǒng)計過程中count發(fā)生了變化,則在采用加鎖的方式來統(tǒng)計所有的元素。如何判斷在統(tǒng)計時容器中的元素發(fā)生改變,使用modcount,在put、remove、clean方法操作元素前都會將變量modcount+1,在比較不加鎖的兩次modcount數(shù)值是否相同,就知道segment數(shù)組中的元素是否發(fā)生過改變。

并發(fā)編程-Java內(nèi)存模型基礎(chǔ)介紹

并發(fā)編程需要處理的兩個關(guān)鍵問題,下船之間如何通信及縣城之間如何同步。這里的現(xiàn)場是指并發(fā)執(zhí)行的活動實體。通信是指線程之間以何種機制來交換信息,在命令式編程中?,F(xiàn)場之間的通信機制有兩種,共享內(nèi)存和消息傳遞。

在共享內(nèi)存的并發(fā)模型里,線程之間共享程序的公共狀態(tài)。通過讀寫內(nèi)存中的公共狀態(tài)進行隱式通信。在消息傳遞的并發(fā)模型里。線程之間沒有公共狀態(tài),線程之間必須通過發(fā)送消息來顯示通信。

同步是指程序中用于控制不同線程將操作發(fā)生相對順序的機制。在共享內(nèi)存并發(fā)模型里,同步是顯示進行的,程序員必須想是指定某個方法或某段代碼。需要在縣城之間互斥進行。在消息傳遞的并發(fā)模型里,由于消息的發(fā)送,必須在消息的接收之前,因此同步是隱式也是進行的。

Java的并發(fā)采用的是共享內(nèi)存模型,Java線程之間的通信總是隱式進行,整個通信過程對程序員完全透明。如果編寫多線程程序的Java程序員不理解隱式進行的線程之間通信的工作機制。很可能會遇到各種奇怪的內(nèi)存可見性問題。

Java并發(fā)編程基礎(chǔ)知識回顧

為什么要使用多線程

  1. 更多的處理器核心
  2. 更快的響應(yīng)時間
  3. 更好的編程模型

Java為多線程編程提供了良好、考究并且一致的編程模型,使開發(fā)人員能夠更加專注于問 題的解決,即為所遇到的問題建立合適的模型,而不是絞盡腦汁地考慮如何將其多線程化。一 旦開發(fā)人員建立好了模型,稍做修改總是能夠方便地映射到Java提供的多線程編程模型上

線程優(yōu)先級

在Java線程中,通過一個整型成員變量priority來控制優(yōu)先級,優(yōu)先級的范圍從1~10,在線 程構(gòu)建的時候可以通過setPriority(int)方法來修改優(yōu)先級,默認(rèn)優(yōu)先級是5,優(yōu)先級高的線程分 配時間片的數(shù)量要多于優(yōu)先級低的線程。設(shè)置線程優(yōu)先級時,針對頻繁阻塞(休眠或者I/O操 作)的線程需要設(shè)置較高優(yōu)先級,而偏重計算(需要較多CPU時間或者偏運算)的線程則設(shè)置較 低的優(yōu)先級,確保處理器不會被獨占。在不同的JVM以及操作系統(tǒng)上,線程規(guī)劃會存在差異, 有些操作系統(tǒng)甚至?xí)雎詫€程優(yōu)先級的設(shè)定

public class Priority {private static volatile boolean notStart = true;private static volatile boolean notEnd = true;public static void main(String[] args) throws Exception { List<Job> jobs = new ArrayList<Job>(); for (int i = 0; i < 10; i++) { int priority = i < 5 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY; Job job = new Job(priority); jobs.add(job); Thread thread = new Thread(job, "Thread:" + i); thread.setPriority(priority); thread.start(); }notStart = false; TimeUnit.SECONDS.sleep(10); notEnd = false; for (Job job : jobs) { System.out.println("Job Priority : " + job.priority + ", Count : " + job.jobCount); } }static class Job implements Runnable {private int priority;private long jobCount;public Job(int priority) {this.priority = priority;}public void run() {while (notStart) {Thread.yield();}while (notEnd) {Thread.yield();jobCount++;}}}
}

運行結(jié)果

在這里插入圖片描述

從輸出可以看到線程優(yōu)先級沒有生效,優(yōu)先級1和優(yōu)先級10的Job計數(shù)的結(jié)果非常相近, 沒有明顯差距。這表示程序正確性不能依賴線程的優(yōu)先級高低。

注意:線程優(yōu)先級不能作為程序正確性的依賴,因為操作系統(tǒng)可以完全不用理會Java 線程對于優(yōu)先級的設(shè)定。

??

什么是線程的上下文切換?

多線程執(zhí)行是cpu搶占時間片的方式執(zhí)行。多線程創(chuàng)建并切換到另一個線程的過程,稱之為線程的上下文切換

如何減少上下文切換

減少上下文切換的方法有無鎖并發(fā)編程、CAS算法、使用最少線程和使用協(xié)程。

  1. 無鎖并發(fā)編程。多線程競爭鎖時,會引起上下文切換,所以多線程處理數(shù)據(jù)時,可以用一 些辦法來避免使用鎖,如將數(shù)據(jù)的ID按照Hash算法取模分段,不同的線程處理不同段的數(shù)據(jù)。
  2. CAS算法。Java的Atomic包使用CAS算法來更新數(shù)據(jù),而不需要加鎖。
  3. 使用最少線程。避免創(chuàng)建不需要的線程,比如任務(wù)很少,但是創(chuàng)建了很多線程來處理,這 樣會造成大量線程都處于等待狀態(tài)
  4. 協(xié)程:在單線程里實現(xiàn)多任務(wù)的調(diào)度,并在單線程里維持多個任務(wù)間的切換

Java 之線程死鎖簡介

死鎖代碼

package aa.testcase;public class DeadLockDemo {private static String A = "A";private static String B = "B";public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (A) {try {Thread.currentThread().sleep(2000);} catch (Exception e) {e.printStackTrace();}//synchronized (B) {System.out.println("BBBBBBBBBBBBb");}}}}) ;Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (B) {synchronized (A) {System.out.println("AAAAAAAA");}}}}) ;t1.start();t2.start();}
}

死鎖出現(xiàn)之后,后續(xù)的代碼就不能正常執(zhí)行。

如何避免死鎖呢?(??嘻嘻)

  1. 避免一個線程同時獲取多個鎖。
  2. 避免一個線程在鎖內(nèi)同時占用多個資源,盡量保證每個鎖只占用一個資源
  3. 嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內(nèi)部鎖機制。
  4. 對于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里,否則會出現(xiàn)解鎖失敗的情況。

資源限制的挑戰(zhàn)

什么是資源限制?

資源限制是指在進行并發(fā)編程時,程序的執(zhí)行速度受限于計算機硬件資源或軟件資源。例如服務(wù)器寬帶只有兩兆每秒。某個資源的下載速度是一兆每秒系統(tǒng)啟動十個線程下載資源,下載速度不會是10m/s,所以在進行并發(fā)編程時要考慮這些資源的限制,硬件資源限制帶有框帶著的上傳下載速度。磁盤讀寫速度和CPU的處理速度,軟件資源限制,有數(shù)據(jù)庫的鏈接書和socket鏈接數(shù)等

資源限制引發(fā)的問題

在并發(fā)編程中間代碼執(zhí)行速度加快的原則,事件代碼中,創(chuàng)新執(zhí)行的部分變成并發(fā)執(zhí)行。倒是如果監(jiān)保段了創(chuàng)新的代碼并發(fā)執(zhí)行,因為受限于資源。仍然在創(chuàng)新執(zhí)行,這時,程序不僅不會加快執(zhí)行,反而會更忙,因為增加了上下文切換和資源調(diào)度的時間。例如,之前看到一個程序使用多線程在辦公網(wǎng)絡(luò)并發(fā)下載和處理數(shù)據(jù)時,導(dǎo)致CPU利用率達百分之百,幾個小時都不能運行完成任務(wù)。后來修改成當(dāng)現(xiàn)場一個小時就執(zhí)行完成了。

如何解決資源限制的問題?

對于硬件資源的限制,可以考慮使用集群并行執(zhí)行程序,既然當(dāng)?shù)氐馁Y源有限,那么就讓程序在多臺機器上運行。比如使用ODPS,還都破獲自己搭建的服務(wù)器集群。不同的機械處理的不同的數(shù)據(jù)??梢酝ㄟ^數(shù)據(jù)id%機器數(shù)。計算得到一個機器編號,然后由對應(yīng)編號的機器處理這筆數(shù)據(jù)。對于軟件資源的限制,可以考慮使用資源池間資源復(fù)用,比如使用鏈接指尖數(shù)據(jù)庫和socket鏈接復(fù)用?;蛘咴僬{(diào)用對方我把service接口獲取數(shù)據(jù)時只建立一個鏈接。

在資源限制情況下進行并發(fā)編

如何在資源限制的情況下讓程序執(zhí)行的更快,方法就是根據(jù)不同的資源調(diào)整。程序的并發(fā)度,例如下載文件上去一那兩個資源,寬帶和硬盤讀寫速度。有數(shù)據(jù)庫操作時涉及數(shù)據(jù)庫鏈接數(shù),如果燒烤語句執(zhí)行非??於F(xiàn)成的。數(shù)量比數(shù)據(jù)庫鏈接數(shù)大很多。則某些線程會被阻塞,等待數(shù)據(jù)庫鏈接。

http://aloenet.com.cn/news/38133.html

相關(guān)文章:

  • 廈門做網(wǎng)站個人蘇州做網(wǎng)站的專業(yè)公司
  • 網(wǎng)站建設(shè)需要什么資料智能營銷方法
  • 松江新城投資建設(shè)集團有限公司網(wǎng)站網(wǎng)絡(luò)營銷第三版課本
  • 龍崗做網(wǎng)站的公司源碼之家
  • 網(wǎng)站建設(shè)到運營需要多少錢怎樣在百度上做廣告
  • 做品牌網(wǎng)站公司淄博網(wǎng)站營銷與推廣
  • 臺州專業(yè)網(wǎng)站設(shè)計系統(tǒng)網(wǎng)絡(luò)推廣有哪幾種方法
  • 做網(wǎng)站品牌怎么注冊自己公司的網(wǎng)址
  • 舟山市城鄉(xiāng)建設(shè)委員會網(wǎng)站seo搜索引擎優(yōu)化是通過優(yōu)化答案
  • 什么網(wǎng)站可以做自考試題seo教育
  • 品牌網(wǎng)站建設(shè)多少錢品牌推廣策略分析
  • 網(wǎng)站怎樣才有流量seo是指搜索引擎營銷
  • 深圳設(shè)計裝修公司哪家好百度關(guān)鍵詞優(yōu)化培訓(xùn)
  • 合肥最好的網(wǎng)站建設(shè)公司化妝培訓(xùn)
  • 上海松江做網(wǎng)站多少錢怎么做百度推廣平臺
  • 網(wǎng)站開發(fā)流程百度文庫北京關(guān)鍵詞優(yōu)化報價
  • 天津網(wǎng)站建設(shè)價格培訓(xùn)課程安排
  • 小縣城做網(wǎng)站百度推廣平臺收費標(biāo)準(zhǔn)
  • 外貿(mào)cms 網(wǎng)站app推廣聯(lián)盟平臺
  • 廣州手機軟件開發(fā)制作初學(xué)seo網(wǎng)站推廣需要怎么做
  • 企業(yè)專屬網(wǎng)頁免費刷seo
  • 國內(nèi)h5 css3網(wǎng)站廣州seo排名收費
  • 鹽城做網(wǎng)站哪家好廣州網(wǎng)站建設(shè)方案維護
  • 怎么做卡蜜網(wǎng)站網(wǎng)站推廣計劃方法
  • 通遼網(wǎng)站建設(shè)tlyltdwindows優(yōu)化大師win10
  • 網(wǎng)站怎么做排名長沙網(wǎng)絡(luò)營銷推廣公司
  • 紹興網(wǎng)站建設(shè)設(shè)計完整html網(wǎng)頁代碼案例
  • 醫(yī)院網(wǎng)站建設(shè)預(yù)算注冊公司
  • 可以做批發(fā)的跨境電商網(wǎng)站平臺今日頭條新聞手機版
  • 網(wǎng)站關(guān)鍵詞搜不到站長seo