1. 程式人生 > >同步程式碼塊和同步方法案例實戰

同步程式碼塊和同步方法案例實戰

什麼是同步

  • 同步就是加鎖,不讓其它人訪問
  • synchronized指的就是同步的意思

什麼情況下需要同步

當多執行緒併發, 我們希望某一段程式碼執行的過程中CPU不要切換到其他執行緒工作. 這時就需要同步,否則會有執行緒安全問題。

同步程式碼塊

  • 使用synchronized關鍵字加上一個鎖物件來定義一段程式碼, 這就叫同步程式碼塊
  • 多個同步程式碼塊如果使用相同的鎖物件, 那麼他們就是同步的
  • 使用同步鎖時,應該盡是讓鎖的範圍小點,才能提高效能

同步程式碼塊案例:

package demo;

public class Task implements
Runnable{ 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 --;
                }
            }
        }
    }*/
}