同步程式碼塊和同步方法案例實戰
阿新 • • 發佈:2018-12-22
什麼是同步
- 同步就是加鎖,不讓其它人訪問
- synchronized指的就是同步的意思
什麼情況下需要同步
當多執行緒併發, 我們希望某一段程式碼執行的過程中CPU不要切換到其他執行緒工作. 這時就需要同步,否則會有執行緒安全問題。
同步程式碼塊
- 使用synchronized關鍵字加上一個鎖物件來定義一段程式碼, 這就叫同步程式碼塊
- 多個同步程式碼塊如果使用相同的鎖物件, 那麼他們就是同步的
- 使用同步鎖時,應該盡是讓鎖的範圍小點,才能提高效能
同步程式碼塊案例:
package demo; public class Task implementsRunnable{ private int tickets = 100; public void run(){ while(true){ synchronized (this){ if(tickets <= 0){ System.out.println("不好意思,票賣完了"); break; }else{ System.out.println(Thread.currentThread()+"恭喜你買到票,票號"+tickets); tickets--; } } } } }
package demo; public class SynchronizedDemo { public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); Thread t2= new Thread(task); Thread t3 = new Thread(task); t1.start(); t2.start(); t3.start(); } }
同步方法
- 使用synchronized關鍵字修飾一個方法, 該方法中所有的程式碼都是同步的
- 非靜態同步方法的鎖是:this
- 靜態同步方法的鎖是:位元組碼物件(xx.class)
案例:賣火車票
- 需求,有A\B\C\D4個視窗同時買票,只有100張票可買
- 多執行緒會有安全問題熟記
//火車站賣票【問題】 /** * 湖南到廣州火車票:今天13:00 ,100張 * 火車站有4個視窗在同時賣票,要保證一張票只能被賣一次 * * 搞4個執行緒表示4個視窗 * * 通過加鎖可以解決被多次賣同一張票的問題 * * 使用同步程式碼塊 */ //建立賣票的任務 TicketTask task = new TicketTask(); //A視窗 Thread t1 = new Thread(task); t1.setName("視窗A"); //B視窗 Thread t2 = new Thread(task); t2.setName("視窗B"); //C視窗 Thread t3 = new Thread(task); t3.setName("視窗C"); //D視窗 Thread t4 = new Thread(task); t4.setName("視窗D"); //開啟執行緒 t1.start(); t2.start(); t3.start(); t4.start(); class TicketTask implements Runnable{ //只有100張票 int ticket = 100; @Override public synchronized void run() { //賣票 while (true) { if (ticket <= 0) { System.out.println("不好意思,票已經賣完了..."); break; } else { System.out.println(Thread.currentThread() + "恭喜你賣到票,票號" + ticket); ticket--; } } } /*@Override public void run() { // TODO Auto-generated method stub *//** * 同步程式碼換括號裡引數可以傳任意物件 * this是一個鎖物件 * 不同的一把鎖,賣相同的票總是還是存在 *//* //賣票 while (true) { synchronized (String.class) {// 同步:加鎖 if (ticket <= 0) { System.out.println("不好意思,票已經賣完了..."); break; } else { System.out.println(Thread.currentThread() + "恭喜你賣到票,票號" + ticket); ticket--; } } } }*/ /*@Override public void run() { // TODO Auto-generated method stub *//** * 同步程式碼換括號裡引數可以傳任意物件 *//* synchronized (this) { //賣票 while(true){ if(ticket <= 0){ System.out.println("不好意思,票已經賣完了..."); break; }else{ System.out.println(Thread.currentThread() + "恭喜你賣到票,票號" + ticket); ticket --; } } } }*/ }