更新時(shí)間:2022-08-08 12:19:31 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1669次
在Java教程中,高并發(fā)編程是一定要學(xué)習(xí)的,下面動(dòng)力節(jié)點(diǎn)小編來(lái)為大家進(jìn)行介紹。
synchronized同步類的不同實(shí)例方法,爭(zhēng)搶的是同一個(gè)monitor的lock,而與之關(guān)聯(lián)的引用是ThisMonitor的實(shí)例引用
package JavaConcurrencyInPractice.book.charpter3;
import java.util.concurrent.TimeUnit;
/**
* @program: JavaLife
* @author: JiaLe Hu
* @create: 2020-12-09 10:38
**/
public class ThisMonitor {
public synchronized void method1() {
System.out.println(Thread.currentThread().getName() + "enter to method1");
try {
TimeUnit.MINUTES.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void method2() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "enter to method1");
try {
TimeUnit.MINUTES.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// public synchronized void method2() {
// System.out.println(Thread.currentThread().getName() + "enter to method2");
// try {
// TimeUnit.MINUTES.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
public static void main(String[] args) {
ThisMonitor thisMonitor = new ThisMonitor();
new Thread(thisMonitor::method1, "T1").start();
new Thread(thisMonitor::method2, "T2").start();
}
}
synchronized同步某個(gè)類的不同靜態(tài)方法爭(zhēng)搶的鎖也是同一個(gè)monitor的lock,該monitor關(guān)聯(lián)的引用是ClassMonitor.class實(shí)例
package JavaConcurrencyInPractice.book.charpter3;
import java.util.concurrent.TimeUnit;
/**
* @program: JavaLife
* @author: JiaLe Hu
* @create: 2020-12-09 10:49
**/
public class ClassMonitor {
public static synchronized void method1() {
System.out.println(Thread.currentThread().getName() + "enter to method1");
try {
TimeUnit.MINUTES.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// public static synchronized void method2() {
// System.out.println(Thread.currentThread().getName() + "enter to method1");
// try {
// TimeUnit.MINUTES.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
public static synchronized void method2() {
synchronized (ClassMonitor.class) {
System.out.println(Thread.currentThread().getName() + "enter to method1");
try {
TimeUnit.MINUTES.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
重入
內(nèi)置鎖是可以重入的,如果某個(gè)線程試圖獲得一個(gè)已經(jīng)由它自己持有的鎖,那么這個(gè)請(qǐng)求就會(huì)成功。重入意味著獲取鎖的操作的粒度是線程。
Wait And notify
wait 方法是可中斷的,當(dāng)前線程一旦調(diào)用了wait方法進(jìn)入阻塞狀態(tài),其他線程是可以使用interrupt方法將其打斷。
線程執(zhí)行了某個(gè)對(duì)象的wait方法,會(huì)加入與之對(duì)應(yīng)的wait set中,每一個(gè)對(duì)象的monitor都有一個(gè)與之關(guān)聯(lián)的wait set
必須在同步方法中使用wait和notify,因?yàn)閳?zhí)行wait和notify的前提條件是必須持有同步方法的monitor的所有權(quán)
wait會(huì)釋放掉monitor的鎖
synchronized 的缺陷
不能控制阻塞的時(shí)間
同步方法不能被中斷,不能像wait和sleep方法一樣,能夠捕獲得到中斷信號(hào)
package LeetCode;
import java.util.concurrent.TimeUnit;
/**
* @program: JavaLife
* @author: JiaLe Hu
* @create: 2020-12-10 09:32
**/
public class synchronizedDefect {
public synchronized void syncMethod() {
try {
System.out.println(Thread.currentThread().getName() + " get this monitor");
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " is interrupted");
}
}
public static void main(String[] args) throws InterruptedException {
synchronizedDefect synchronizedDefect = new synchronizedDefect();
Thread t1 = new Thread(synchronizedDefect::syncMethod, "t1");
t1.start();
TimeUnit.MILLISECONDS.sleep(2);
Thread t2 = new Thread(synchronizedDefect::syncMethod, "t2");
t2.start();
TimeUnit.MILLISECONDS.sleep(2);
t2.interrupt();
System.out.println(t2.isInterrupted()); // true
System.out.println(t2.getState()); // BLOCKED
}
}
該ThreadGroup如果有父ThreadGroup,則直接調(diào)用父Group的uncaughtException方法
如果設(shè)置了全局默認(rèn)的UncaughtException,則會(huì)調(diào)用全局的uncaughtException方法
若既沒(méi)有父ThreadGroup,也沒(méi)有全局默認(rèn)的UncaughtException,直接將異常的堆棧信息定向到System.err中
Hook注入(Runtime)
package JavaConcurrencyInPractice.book.charpter4;
import java.util.concurrent.TimeUnit;
/**
* @program: JavaLife
* @author: JiaLe Hu
* @create: 2020-12-11 11:05
**/
public class ThreadHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
System.out.println("The hook thread 1 is running ");
TimeUnit.SECONDS.sleep(1);
System.out.println("The hook thread 1 will exit");
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
System.out.println("The hook thread 2 is running ");
TimeUnit.SECONDS.sleep(2);
System.out.println("The hook thread 2 will exit");
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
System.out.println("program is exiting");
}
}
Hook線程應(yīng)用場(chǎng)景以及注意事項(xiàng)
Hook線程只有在收到推出信號(hào)的時(shí)候會(huì)被執(zhí)行,如果在kill的時(shí)候使用了參數(shù)-9,那么Hook線程不會(huì)執(zhí)行,進(jìn)程將立即退出,因此lock文件不會(huì)被刪除
Hook線程中也可以執(zhí)行一些資源釋放的工作,比如關(guān)閉文件句柄、socket鏈接、數(shù)據(jù)庫(kù)connection
盡量不要在Hook線程中執(zhí)行一些耗時(shí)非常長(zhǎng)的操作。因此會(huì)導(dǎo)致程序遲遲不能退出。
使用new關(guān)鍵字會(huì)導(dǎo)致類的初始化
訪問(wèn)類的靜態(tài)變量
訪問(wèn)類的靜態(tài)方法,會(huì)導(dǎo)致類的初始化
對(duì)某個(gè)類進(jìn)行反射
初始化子類會(huì)導(dǎo)致父類的初始化(通過(guò)子類的靜態(tài)變量只會(huì)導(dǎo)致父類的初始化)
啟動(dòng)類
除了上述的6種情況,其余都被稱為被動(dòng)使用,不會(huì)導(dǎo)致類的加載和初始化
類的加載階段
class文件種的二進(jìn)制數(shù)據(jù)讀取到內(nèi)存中,然后將該字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)中的運(yùn)行時(shí)的數(shù)據(jù)結(jié)構(gòu),并且在堆內(nèi)存中生成一個(gè)該類的java.lang.Class對(duì)象,作為訪問(wèn)方法區(qū)數(shù)據(jù)結(jié)構(gòu)的入口。加載過(guò)程常伴隨著連接階段交叉工作。
類初始化的階段
包含了所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊的執(zhí)行代碼
靜態(tài)語(yǔ)句塊只能對(duì)后面的靜態(tài)變量進(jìn)行賦值,但是不能對(duì)其訪問(wèn)。父類的靜態(tài)變量總是能夠得到優(yōu)先賦值。
根加載器
根加載器又被稱為Bootstrap類加載器,該類加載器是最為頂層的加載器,其沒(méi)有父加載器,它是由C++編寫(xiě)的,主要負(fù)責(zé)虛擬機(jī)核心類庫(kù)的加載-Xbootclasspath來(lái)指定根加載器的路徑
擴(kuò)展類加載器
擴(kuò)展類加載器的父加載器是根加載器,主要用于加載JAVA_HOME下jre/lb/ext子目錄里面的類庫(kù)。由純Java語(yǔ)言實(shí)現(xiàn)
系統(tǒng)類加載器
負(fù)責(zé)加載classpath下的類庫(kù)資源
如果大家想了解更多相關(guān)知識(shí),可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java多線程并發(fā)編程,里面有更豐富的知識(shí)等著大家去學(xué)習(xí),希望對(duì)大家能夠有所幫助。
相關(guān)閱讀
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)