同步鎖機制:
在《Thinking in Java》中,是這麼說的:對於併發工做,你須要某種方式來防
止兩個任務訪問相同的資源(其實就是共享資源競爭)。 防止這種衝突的方法
就是當資源被一個任務使用時,在其上加鎖。第一個訪問某項資源的任務必須
鎖定這項資源,使其餘任務在其被解鎖以前,就沒法訪問它了,而在其被解鎖
之時,另外一個任務就能夠鎖定並使用它了。
synchronized 的鎖是什麼 ?
任意對象均可以做爲同步鎖。全部對象都自動含有單一的鎖(監視器)。
同步方法的鎖:靜態方法(類名.class)、非靜態方法(this)
同步代碼塊:本身指定,不少時候也是指定爲this或類名.class
注意:
必須確保使用同一個資源的 多個線程共用一把鎖,這個很是重要,不然就
沒法保證共享資源的安全
一個線程類中的全部靜態方法共用同一把鎖(類名.class),全部非靜態方
法共用同一把鎖(this),同步代碼塊(指定需謹慎)java
使用同步代碼塊解決繼承Thread類的方式的線程安全問題
package com.atguigu.java; /** * 使用同步代碼塊解決繼承Thread類的方式的線程安全問題 * * 例子:建立三個窗口賣票,總票數爲100張.使用繼承Thread類的方式 * * 說明:在繼承Thread類建立多線程的方式中,慎用this充當同步監視器,考慮使用當前類充當同步監視器。 * * @author ch * @create 2021-02-13 下午 4:20 */ class Window2 extends Thread{ private static int ticket = 100; private static Object obj = new Object(); @Override public void run() { while(true){ //正確的 // synchronized (obj){ synchronized (Window2.class){//Class clazz = Window2.class,Window2.class只會加載一次 //錯誤的方式:this表明着t1,t2,t3三個對象 // synchronized (this){ if(ticket > 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":賣票,票號爲:" + ticket); ticket--; }else{ break; } } } } } public class WindowTest2 { public static void main(String[] args) { Window2 t1 = new Window2(); Window2 t2 = new Window2(); Window2 t3 = new Window2(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }
使用同步方法解決實現Runnable接口的線程安全問題
package com.atguigu.java; /** * 使用同步方法解決實現Runnable接口的線程安全問題 * * * 關於同步方法的總結: * 1. 同步方法仍然涉及到同步監視器,只是不須要咱們顯式的聲明。 * 2. 非靜態的同步方法,同步監視器是:this * 靜態的同步方法,同步監視器是:當前類自己 * * @author ch * @create 2021-02-15 上午 11:35 */ class Window3 implements Runnable { private int ticket = 100; @Override public void run() { while (true) { show(); } } private synchronized void show(){//同步監視器:this //synchronized (this){ if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":賣票,票號爲:" + ticket); ticket--; } //} } } public class WindowTest3 { public static void main(String[] args) { Window3 w = new Window3(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }
使用同步方法處理繼承Thread類的方式中的線程安全問題
package com.atguigu.java; /** * 使用同步方法處理繼承Thread類的方式中的線程安全問題 * * @author ch * @create 2021-02-15 上午 11:43 */ class Window4 extends Thread { private static int ticket = 100; @Override public void run() { while (true) { show(); } } private static synchronized void show(){//同步監視器:Window4.class //private synchronized void show(){ //同步監視器:t1,t2,t3。此種解決方式是錯誤的 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":賣票,票號爲:" + ticket); ticket--; } } } public class WindowTest4 { public static void main(String[] args) { Window4 t1 = new Window4(); Window4 t2 = new Window4(); Window4 t3 = new Window4(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }