java線程安全之synchronized

本篇文章轉載自時間斷崖
synchronized是java中解決併發問題的一種最簡單最經常使用的方法,他能夠確保線程互斥的訪問同步代碼html

synchronized的三種應用方式

同步代碼塊: 鎖是括號裏面的對象,對給定對象加鎖,進入同步代碼以前要得到給定對象的鎖 同步普通方法: 鎖是當前實例對象,進入同步代碼以前要得到當前實例的鎖 同步靜態方法: 鎖是當前類的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張的時候就中止賣票了。測試

  1. 同步代碼塊
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;
                }
            }
        }
    }
}
  1. 同步普通方法
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--);
        }
    }
}
  1. 同步靜態方法
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--);
        }
    }
}
  1. 測試代碼
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

相關文章
相關標籤/搜索