本篇文章轉載自時間斷崖
synchronized是java中解決併發問題的一種最簡單最經常使用的方法,他能夠確保線程互斥的訪問同步代碼html
同步代碼塊: 鎖是括號裏面的對象,對給定對象加鎖,進入同步代碼以前要得到給定對象的鎖 同步普通方法: 鎖是當前實例對象,進入同步代碼以前要得到當前實例的鎖 同步靜態方法: 鎖是當前類的class對象,進入同步代碼以前要得到當前類對象的鎖java
當不使用synchronized關鍵字的時候會發生什麼併發
public class Ticket implements Runnable{ private int tickets = 10;//定義變量tickets,並賦值10 public void run() { while (true) { saleTicket(); if (tickets <= 0) { break; } } } public void saleTicket () { if (tickets > 0) { try { Thread.sleep(10); //通過的線程休眠 10秒 }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---賣出的票"+tickets--); } } }
結果: 線程二---賣出的票10 線程一---賣出的票9 線程四---賣出的票8 線程三---賣出的票8 線程二---賣出的票7 線程一---賣出的票6 線程三---賣出的票5 線程四---賣出的票4 線程二---賣出的票2 線程一---賣出的票3 線程四---賣出的票1 線程三---賣出的票1 線程一---賣出的票0 線程二---賣出的票-1
能夠看到賣出了0和-1張票,還賣了好幾張1,在代碼邏輯中當賣到0張的時候就中止賣票了。測試
public class Ticket implements Runnable{ private int tickets = 10;//定義變量tickets,並賦值10 Object lock = new Object();//定義任意一個對象,用做同步代碼的鎖 public void run() { while (true) { synchronized (lock) { //定義同步代碼塊 try { Thread.sleep(10); //通過的線程休眠 10秒 }catch (InterruptedException e) { e.printStackTrace(); } if (tickets > 0) { System.out.println(Thread.currentThread().getName()+"---賣出的票"+tickets--); }else {//若是tickets小於0,跳出循環 break; } } } } }
public class Ticket implements Runnable{ private int tickets = 10;//定義變量tickets,並賦值10 public void run() { while (true) { saleTicket(); if (tickets <= 0) { break; } } } public synchronized void saleTicket () { if (tickets > 0) { try { Thread.sleep(10); //通過的線程休眠 10秒 }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---賣出的票"+tickets--); } } }
public class Ticket implements Runnable{ private static int tickets = 10;//定義變量tickets,並賦值10 public void run() { while (true) { saleTicket(); if (tickets <= 0) { break; } } } public static synchronized void saleTicket () { if (tickets > 0) { try { Thread.sleep(10); //通過的線程休眠 10秒 }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---賣出的票"+tickets--); } } }
public class TestTicket{ public static void main(String[] args) { Ticket ticket = new Ticket();//建立ticket對象 //建立4個線程 new Thread(ticket,"線程一").start(); new Thread(ticket,"線程二").start(); new Thread(ticket,"線程三").start(); new Thread(ticket,"線程四").start(); } }
測試結果:線程
線程一---賣出的票10 線程一---賣出的票9 線程四---賣出的票8 線程四---賣出的票7 線程四---賣出的票6 線程四---賣出的票5 線程四---賣出的票4 線程四---賣出的票3 線程四---賣出的票2 線程四---賣出的票1
能夠看到賣票結果沒有超出預期code