您好,登錄后才能下訂單哦!
這篇“Java Thread多線程開發中Object類怎么使用”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java Thread多線程開發中Object類怎么使用”文章吧。
使用了wait方法之后,線程就會進入阻塞階段,只有發生以下四種情況中的其中一個,線程才會被喚醒
另一個線程調用了這個線程的notify方法,剛好喚醒的是本線程
另一個線程調用了這個對象的notifyAll方法
過了wait規定的超時時間
線程調用了interrupt
notify會喚醒單個處于阻塞狀態的線程,喚醒的線程是隨機的
notify和wait都需要寫在synchronized代碼塊里,不然會拋出異常
notifyAll會喚醒所有等待的線程
執行wait方法之后,被中斷,會拋出InterruptedException這個異常
展示wait和notify的基本用法
該代碼執行wait方法之后會釋放鎖,然后thread2執行notify方法
notify方法執行完畢之后,并沒有立即釋放鎖,而是接著執行之后的代碼,也就是打印“Thread2調用notify”這句話
thread2執行完畢之后,會進行釋放鎖,thread1才會繼續執行
在此期間,thread1雖然被喚醒,但是一直在等待thread2同步代碼塊里面的代碼執行完畢
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執行"); 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調用notify"); } } } } /* Thread1執行 Thread2調用notify Thread1獲取鎖 * */
notify和notifyAll的展示
第一個輸出:threadc調用notifyAll
第二個輸出:threadc調用notify
調用notify的時候,程序并沒有結束,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結束"); } catch (InterruptedException e) { e.printStackTrace(); } } } } /* Thread-0得到鎖 Thread-0wait Thread-1得到鎖 Thread-1wait Thread-2notifyAll Thread-1wait結束 Thread-0wait結束 * */ /* Thread-0得到鎖 Thread-0wait Thread-1得到鎖 Thread-1wait Thread-2notify Thread-0wait結束 * */
只釋放當前monitor
證明wait只釋放當前的那把鎖
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 * */
執行這些方法必須先獲取鎖
notify只能換取一個,而且是隨機的
都屬于Object。任何對象都可以調用
都是native final修飾的
當線程從wait狀態剛被喚醒時,通常不能直接得到鎖,那就會從waiting狀態轉換到blocked狀態,搶到鎖之后狀態轉變為runnable
如果發生異常,則直接跳到Terminated狀態
將storge當作生產者和消費者進行工作的倉庫
如果storge中沒有數據,生產者就開始wait
如果storge中數據滿了,消費者就開始wait
生產者和消費者每進行一次生產和消費,就執行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("已經有了" + 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(); } }
作用:讓線程在預期的時間執行,其他時間不占用CPU資源
特點:和wait不一樣,sleep不釋放鎖
證明sleep不會釋放 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釋放鎖 * */
拋出InterruptedException
會清除中斷狀態
中斷之后,拋出異常繼續執行
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 * */
sleep方法可以讓線程進入waiting狀態,不占用CPU資源,但是不釋放鎖,規定時間之后再運行
休眠期間如果被打斷,會拋出異常并清除中斷狀態
新線程加入,主線程等子線程執行完畢
前一個結果是使用join
后一個結果是沒使用join
可知使用join之后,主線程會等join的線程執行完畢再繼續執行
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() + "執行完畢"); } }); 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() + "執行完畢"); } }); thread1.start(); thread2.start(); System.out.println("開始等待子線程運行"); // thread1.join(); // thread2.join(); System.out.println("所有線程執行完畢"); } } /* * 開始等待子線程運行 Thread-0執行完畢 Thread-1執行完畢 所有線程執行完畢 * */ /* * 開始等待子線程運行 所有線程執行完畢 Thread-1執行完畢 Thread-0執行完畢 * */
遇到中斷
第一個的運行結果是主線程沒中斷的打印結果
第二個的運行結果是join期間進行中斷的打印結果,可知在打印了“子線程運行完畢”之后,依然打印了“啟動”兩個字,可知會造成運行混亂
可以在捕獲異常的代碼塊中,將join的線程也中斷,可以解決上面的問題
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("啟動"); } 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("子線程運行完畢"); } } /* * join 啟動 子線程運行完畢 * */ /* * join main中斷 子線程運行完畢 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 main中斷 子線程運行完畢 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期間,線程處于WAITING狀態
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("子線程運行結束"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); System.out.println("join"); thread.join(); System.out.println("運行完畢"); } } /* * join WAITING 子線程運行結束 運行完畢 * */
用來釋放CPU時間片,但是不一定能達到預期的效果,因為有時CPU資源不緊張,無需yield
和sleep的區別是:sleep期間不會被再次調度但是yield會立刻處于競爭狀態,還會隨時再次被調度
以上就是關于“Java Thread多線程開發中Object類怎么使用”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。