Java Thread多線(xiàn)程開(kāi)發(fā)中Object類(lèi)詳細(xì)講解
方法概覽
Thread

wait notify notifyAll方法詳解
作用
阻塞階段
使用了wait方法之后,線(xiàn)程就會(huì)進(jìn)入阻塞階段,只有發(fā)生以下四種情況中的其中一個(gè),線(xiàn)程才會(huì)被喚醒
- 另一個(gè)線(xiàn)程調(diào)用了這個(gè)線(xiàn)程的notify方法,剛好喚醒的是本線(xiàn)程
- 另一個(gè)線(xiàn)程調(diào)用了這個(gè)對(duì)象的notifyAll方法
- 過(guò)了wait規(guī)定的超時(shí)時(shí)間
- 線(xiàn)程調(diào)用了interrupt
喚醒階段
notify會(huì)喚醒單個(gè)處于阻塞狀態(tài)的線(xiàn)程,喚醒的線(xiàn)程是隨機(jī)的
notify和wait都需要寫(xiě)在synchronized代碼塊里,不然會(huì)拋出異常
notifyAll會(huì)喚醒所有等待的線(xiàn)程
遇到中斷
執(zhí)行wait方法之后,被中斷,會(huì)拋出InterruptedException這個(gè)異常
代碼展示
- 展示wait和notify的基本用法
- 該代碼執(zhí)行wait方法之后會(huì)釋放鎖,然后thread2執(zhí)行notify方法
- notify方法執(zhí)行完畢之后,并沒(méi)有立即釋放鎖,而是接著執(zhí)行之后的代碼,也就是打印“Thread2調(diào)用notify”這句話(huà)
- thread2執(zhí)行完畢之后,會(huì)進(jìn)行釋放鎖,thread1才會(huì)繼續(xù)執(zhí)行
- 在此期間,thread1雖然被喚醒,但是一直在等待thread2同步代碼塊里面的代碼執(zhí)行完畢
public class Wait {
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
Thread.sleep(200);
thread2.start();
}
public static Object object = new Object();
static class Thread1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("Thread1執(zhí)行");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1獲取鎖");
}
}
}
static class Thread2 extends Thread {
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println("Thread2調(diào)用notify");
}
}
}
}
/*
Thread1執(zhí)行
Thread2調(diào)用notify
Thread1獲取鎖
* */
- notify和notifyAll的展示
- 第一個(gè)輸出:threadc調(diào)用notifyAll
- 第二個(gè)輸出:threadc調(diào)用notify
- 調(diào)用notify的時(shí)候,程序并沒(méi)有結(jié)束,threadb陷入等待
public class notifyOrAll implements Runnable{
private static final Object a = new Object();
public static void main(String[] args) throws InterruptedException {
Runnable r = new notifyOrAll();
Thread threada = new Thread(r);
Thread threadb = new Thread(r);
Thread threadc = new Thread(new Runnable() {
@Override
public void run() {
synchronized (a) {
// a.notifyAll();
a.notify();
System.out.println(Thread.currentThread().getName() + "notify");
}
}
});
threada.start();
Thread.sleep(200);
threadb.start();
Thread.sleep(200);
threadc.start();
}
@Override
public void run() {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "得到鎖");
try {
System.out.println(Thread.currentThread().getName() + "wait");
a.wait();
System.out.println(Thread.currentThread().getName() + "wait結(jié)束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
Thread-0得到鎖
Thread-0wait
Thread-1得到鎖
Thread-1wait
Thread-2notifyAll
Thread-1wait結(jié)束
Thread-0wait結(jié)束
* */
/*
Thread-0得到鎖
Thread-0wait
Thread-1得到鎖
Thread-1wait
Thread-2notify
Thread-0wait結(jié)束
* */- 只釋放當(dāng)前monitor
- 證明wait只釋放當(dāng)前的那把鎖
public class OwnMonitor {
private static volatile Object a = new Object();
private static volatile Object b = new Object();
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
synchronized (a) {
System.out.println("threadA得到a");
synchronized (b) {
System.out.println("threadA得到鎖b");
try {
System.out.println("threadA釋放a");
a.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
synchronized (a) {
System.out.println("threadB得到a");
System.out.println("threadB要獲取b");
synchronized (b) {
System.out.println("threadB得到b");
}
}
}
});
threadA.start();
Thread.sleep(1000);
threadB.start();
}
}
/*
threadA得到a
threadA得到鎖b
threadA釋放a
threadB得到a
threadB要獲取b
* */
特點(diǎn)
- 執(zhí)行這些方法必須先獲取鎖
- notify只能換取一個(gè),而且是隨機(jī)的
- 都屬于Object。任何對(duì)象都可以調(diào)用
- 都是native final修飾的
當(dāng)線(xiàn)程從wait狀態(tài)剛被喚醒時(shí),通常不能直接得到鎖,那就會(huì)從waiting狀態(tài)轉(zhuǎn)換到blocked狀態(tài),搶到鎖之后狀態(tài)轉(zhuǎn)變?yōu)閞unnable
如果發(fā)生異常,則直接跳到Terminated狀態(tài)
通過(guò)wait notify方法實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者
- 將storge當(dāng)作生產(chǎn)者和消費(fèi)者進(jìn)行工作的倉(cāng)庫(kù)
- 如果storge中沒(méi)有數(shù)據(jù),生產(chǎn)者就開(kāi)始wait
- 如果storge中數(shù)據(jù)滿(mǎn)了,消費(fèi)者就開(kāi)始wait
- 生產(chǎn)者和消費(fèi)者每進(jìn)行一次生產(chǎn)和消費(fèi),就執(zhí)行notify
public class ProducerConsumer {
public static void main(String[] args) {
Storge storge = new Storge();
Producer producer = new Producer(storge);
Consumer consumer = new Consumer(storge);
new Thread(producer).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private Storge storge;
public Producer(Storge storge) {
this.storge = storge;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storge.put();
}
}
}
class Consumer implements Runnable {
private Storge storge;
public Consumer(Storge storge) {
this.storge = storge;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storge.take();
}
}
}
class Storge {
private int maxSize;
private LinkedList<Date> storge;
public Storge() {
maxSize = 10;
storge = new LinkedList<>();
}
public synchronized void put() {
while (storge.size() == maxSize) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storge.add(new Date());
System.out.println("已經(jīng)有了" + storge.size());
notify();
}
public synchronized void take() {
while (storge.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("拿到了" + storge.poll() + "還剩" + storge.size());
notify();
}
}
sleep方法詳解
作用:讓線(xiàn)程在預(yù)期的時(shí)間執(zhí)行,其他時(shí)間不占用CPU資源
特點(diǎn):和wait不一樣,sleep不釋放鎖
sleep不會(huì)釋放鎖
證明sleep不會(huì)釋放 synchronized鎖
public class SleepSyn implements Runnable{
public static void main(String[] args) {
SleepSyn sleepSyn = new SleepSyn();
new Thread(sleepSyn).start();
new Thread(sleepSyn).start();
}
@Override
public void run() {
syn();
}
private synchronized void syn() {
System.out.println(Thread.currentThread().getName() + "獲取鎖");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "釋放鎖");
}
}
/*
* Thread-0獲取鎖
Thread-0釋放鎖
Thread-1獲取鎖
Thread-1釋放鎖
* */
證明sleep不釋放Lock鎖
public class sleepLock implements Runnable{
private static final Lock LOCK = new ReentrantLock();
@Override
public void run() {
LOCK.lock();
System.out.println(Thread.currentThread().getName() + "獲取鎖");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
LOCK.unlock();
}
System.out.println(Thread.currentThread().getName() + "釋放鎖");
}
public static void main(String[] args) {
sleepLock sleepLock = new sleepLock();
new Thread(sleepLock).start();
new Thread(sleepLock).start();
}
}
/*
* Thread-0獲取鎖
Thread-0釋放鎖
Thread-1獲取鎖
Thread-1釋放鎖
* */
sleep響應(yīng)中斷
- 拋出InterruptedException
- 會(huì)清除中斷狀態(tài)
- 中斷之后,拋出異常繼續(xù)執(zhí)行
public class sleepInterrupted implements Runnable{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new sleepInterrupted());
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("中斷");
e.printStackTrace();
}
}
}
}
/*
* Fri Jan 27 21:11:57 CST 2023
Fri Jan 27 21:11:58 CST 2023
中斷
Fri Jan 27 21:11:59 CST 2023
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.jx.JavaTest.ThreadObjectMethod.sleepInterrupted.run(sleepInterrupted.java:21)
at java.lang.Thread.run(Thread.java:748)
Fri Jan 27 21:12:00 CST 2023
Fri Jan 27 21:12:01 CST 2023
Fri Jan 27 21:12:02 CST 2023
Fri Jan 27 21:12:03 CST 2023
Fri Jan 27 21:12:04 CST 2023
Fri Jan 27 21:12:05 CST 2023
Fri Jan 27 21:12:06 CST 2023
Process finished with exit code 0
* */總結(jié)
sleep方法可以讓線(xiàn)程進(jìn)入waiting狀態(tài),不占用CPU資源,但是不釋放鎖,規(guī)定時(shí)間之后再運(yùn)行
休眠期間如果被打斷,會(huì)拋出異常并清除中斷狀態(tài)
join方法詳解
新線(xiàn)程加入,主線(xiàn)程等子線(xiàn)程執(zhí)行完畢
代碼展示
- 前一個(gè)結(jié)果是使用join
- 后一個(gè)結(jié)果是沒(méi)使用join
- 可知使用join之后,主線(xiàn)程會(huì)等join的線(xiàn)程執(zhí)行完畢再繼續(xù)執(zhí)行
public class join {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "執(zhí)行完畢");
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "執(zhí)行完畢");
}
});
thread1.start();
thread2.start();
System.out.println("開(kāi)始等待子線(xiàn)程運(yùn)行");
// thread1.join();
// thread2.join();
System.out.println("所有線(xiàn)程執(zhí)行完畢");
}
}
/*
* 開(kāi)始等待子線(xiàn)程運(yùn)行
Thread-0執(zhí)行完畢
Thread-1執(zhí)行完畢
所有線(xiàn)程執(zhí)行完畢
* */
/*
* 開(kāi)始等待子線(xiàn)程運(yùn)行
所有線(xiàn)程執(zhí)行完畢
Thread-1執(zhí)行完畢
Thread-0執(zhí)行完畢
* */- 遇到中斷
- 第一個(gè)的運(yùn)行結(jié)果是主線(xiàn)程沒(méi)中斷的打印結(jié)果
- 第二個(gè)的運(yùn)行結(jié)果是join期間進(jìn)行中斷的打印結(jié)果,可知在打印了“子線(xiàn)程運(yùn)行完畢”之后,依然打印了“啟動(dòng)”兩個(gè)字,可知會(huì)造成運(yùn)行混亂
- 可以在捕獲異常的代碼塊中,將join的線(xiàn)程也中斷,可以解決上面的問(wèn)題
public class joinInterrupt {
public static void main(String[] args) {
Thread main1 = Thread.currentThread();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
main1.interrupt();
Thread.sleep(2000);
System.out.println("啟動(dòng)");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
System.out.println("join");
try {
thread1.join();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "中斷");
// thread1.interrupt();
e.printStackTrace();
}
System.out.println("子線(xiàn)程運(yùn)行完畢");
}
}
/*
* join
啟動(dòng)
子線(xiàn)程運(yùn)行完畢
* */
/*
* join
main中斷
子線(xiàn)程運(yùn)行完畢
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1252)
at java.lang.Thread.join(Thread.java:1326)
at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt.main(joinInterrupt.java:23)
啟動(dòng)
Process finished with exit code 0
* */
/*
* join
main中斷
子線(xiàn)程運(yùn)行完畢
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt$1.run(joinInterrupt.java:13)
at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1252)
at java.lang.Thread.join(Thread.java:1326)
at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt.main(joinInterrupt.java:23)
Process finished with exit code 0
* */join期間,線(xiàn)程處于WAITING狀態(tài)
public class joinStates {
public static void main(String[] args) throws InterruptedException {
Thread main1 = Thread.currentThread();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println(main1.getState());
System.out.println("子線(xiàn)程運(yùn)行結(jié)束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
System.out.println("join");
thread.join();
System.out.println("運(yùn)行完畢");
}
}
/*
* join
WAITING
子線(xiàn)程運(yùn)行結(jié)束
運(yùn)行完畢
* */
yield方法
用來(lái)釋放CPU時(shí)間片,但是不一定能達(dá)到預(yù)期的效果,因?yàn)橛袝r(shí)CPU資源不緊張,無(wú)需yield
和sleep的區(qū)別是:sleep期間不會(huì)被再次調(diào)度但是yield會(huì)立刻處于競(jìng)爭(zhēng)狀態(tài),還會(huì)隨時(shí)再次被調(diào)度
到此這篇關(guān)于Java Thread多線(xiàn)程開(kāi)發(fā)中Object類(lèi)詳細(xì)講解的文章就介紹到這了,更多相關(guān)Java Object類(lèi)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java跨平臺(tái)原理與虛擬機(jī)相關(guān)簡(jiǎn)介
這篇文章主要介紹了Java跨平臺(tái)原理與虛擬機(jī)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03
SpringBoot靜態(tài)資源css,js,img配置方案
這篇文章主要介紹了SpringBoot靜態(tài)資源css,js,img配置方案,下文給大家分享了三種解決方案,需要的朋友可以參考下2017-07-07
關(guān)于fastjson的@JSONField注解的一些問(wèn)題(詳解)
下面小編就為大家?guī)?lái)一篇關(guān)于fastjson的@JSONField注解的一些問(wèn)題(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
java.lang.UnsupportedClassVersionError異常正確解決方法
java.lang.UnsupportedClassVersionError異常通常發(fā)生在嘗試在較低版本的Java虛擬機(jī)上運(yùn)行使用更高版本的Jav 編譯器編譯的類(lèi)文件時(shí),下面就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-05-05
Java利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏詳解
在項(xiàng)目中有些敏感信息不能直接展示,比如客戶(hù)手機(jī)號(hào)、身份證、車(chē)牌號(hào)等信息,展示時(shí)均需要進(jìn)行數(shù)據(jù)脫敏,防止泄露客戶(hù)隱私。本文將利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏,需要的可以參考一下2023-03-03
SpringBoot+fileUpload獲取文件上傳進(jìn)度
這篇文章主要為大家詳細(xì)介紹了SpringBoot+fileUpload獲取文件上傳進(jìn)度,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08

