多線程基礎講解五: synchronized使用

多線程的鎖有: synchronized 和 jdk1.5的Lock

 

先說synchronized的各種用法:

1. 使用任意同一對象做鎖  (一定要是同一對象)

2. 使用this做鎖

3. class字節碼文件做鎖

4. 靜態同步代碼塊做鎖    (原理其實就是:class字節碼文件做鎖)

5.非靜態同步代碼塊做鎖 (原理其實就是:使用this做鎖)

 

任意對象做鎖例子:

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class TicketRunnable implements Runnable {

    /**
     * 需求現在有100張火車票,有兩個窗口同時搶火車票,請使用多線程模擬搶票效果。
     */
    int tickets = 100;
    private Object obj = new Object();

    public void run() {

        while (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sale();
        }
    }

    public void sale() {

        /**
         * 使用任意、同一對象做鎖
         */
        synchronized (obj) {
            /**
             * 最後判斷一下,還是因爲有線程安全的問題。
             *
             * 最後一張票賣完後,tickets = 0,但是這時候,最後一個等待的線程剛剛就就進來了,所以會得到100 - 0 + 1  ,結果爲101的票,所以在這裏判斷一下。
             * 還有一個辦法,就是在  while (tickets > 0) 之前就加 synchronized。
             * 但是使用synchronized最好包裹的代碼很少,所以就這樣寫了。
             * 又如果在while那裏就包裹了,多半這個代碼直接就一個線程執行完了。
             */
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
                tickets--;
            }
        }
    }
}

 

this做鎖的例子:

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class TicketRunnable implements Runnable {

    /**
     * 需求現在有100張火車票,有兩個窗口同時搶火車票,請使用多線程模擬搶票效果。
     */
    int tickets = 100;

    public void run() {

        while (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sale();
        }
    }

    public void sale() {

        /**
         * this做鎖
         */
        synchronized (this) {
            /**
             * 最後判斷一下,還是因爲有線程安全的問題。
             *
             * 最後一張票賣完後,tickets = 0,但是這時候,最後一個等待的線程剛剛就就進來了,所以會得到100 - 0 + 1  ,結果爲101的票,所以在這裏判斷一下。
             * 還有一個辦法,就是在  while (tickets > 0) 之前就加 synchronized。
             * 但是使用synchronized最好包裹的代碼很少,所以就這樣寫了。
             * 又如果在while那裏就包裹了,多半這個代碼直接就一個線程執行完了。
             */
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
                tickets--;
            }
        }
    }
}

 

class字節碼文件做鎖的例子:

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class TicketRunnable implements Runnable {

    /**
     * 需求現在有100張火車票,有兩個窗口同時搶火車票,請使用多線程模擬搶票效果。
     */
    int tickets = 100;
    private Object obj = new Object();

    public void run() {

        while (tickets > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sale();
        }
    }

    public void sale() {

        /**
         * class文件做鎖
         */
        synchronized (TicketRunnable.class) {
            /**
             * 最後判斷一下,還是因爲有線程安全的問題。
             *
             * 最後一張票賣完後,tickets = 0,但是這時候,最後一個等待的線程剛剛就就進來了,所以會得到100 - 0 + 1  ,結果爲101的票,所以在這裏判斷一下。
             * 還有一個辦法,就是在  while (tickets > 0) 之前就加 synchronized。
             * 但是使用synchronized最好包裹的代碼很少,所以就這樣寫了。
             * 又如果在while那裏就包裹了,多半這個代碼直接就一個線程執行完了。
             */
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
                tickets--;
            }
        }
    }
}

 

 

靜態同步代碼塊做鎖: (並證明原理爲 字節碼文件爲鎖)

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class TicketRunnable implements Runnable {

    /**
     * 需求現在有100張火車票,有兩個窗口同時搶火車票,請使用多線程模擬搶票效果。
     * <p>
     * 使用靜態變量
     */
    private static int tickets = 100;

    private Object obj = new Object();

    public void run() {

        while (tickets > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (tickets % 2 != 0) {
                synchronized (TicketRunnable.class) {
                    if (tickets > 0) {
                        System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
                        tickets--;
                    }
                }
            } else {
                sale();
            }
        }
    }

    /**
     * 定義靜態同步代碼塊
     * 在方法上,加上 static  和  synchronized。
     * <p>
     * 原理: 這個其實就是使用的字節碼文件做鎖。
     * <p>
     * 怎麼證明呢 ? 可以寫兩個線程,一個使用字節碼文件做鎖,一個使用靜態同步代碼塊,如果完成了同步功能,就證明靜態同步代碼快使用的是 字節碼文件做鎖。
     * <p>
     * 在工作中,不推薦使用靜態同步鎖,因爲靜態方法不會被回收。
     * 建議使用 非靜態同步代碼塊做鎖;
     */
    public static synchronized void sale() {

        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
            tickets--;
        }
    }
}

 

 

非靜態同步代碼塊做鎖:(並證明原理爲: this做鎖)

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class TicketRunnable implements Runnable {

    /**
     * 需求現在有100張火車票,有兩個窗口同時搶火車票,請使用多線程模擬搶票效果。
     * <p>
     * 使用靜態變量
     */
    private int tickets = 100;

    private Object obj = new Object();

    public void run() {

        while (tickets > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            /**
             * 使用判斷,證明非靜態同步代碼快使用的是this鎖
             */
            if (tickets % 2 != 0) {
                synchronized (this) {
                    if (tickets > 0) {
                        System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
                        tickets--;
                    }
                }
            } else {
                sale();
            }
        }
    }

    /**
     * 定義非靜態同步代碼塊
     * 在方法上,加上 synchronized。
     * <p>
     * 原理: 這個其實就是使用的this鎖。
     * <p>
     * 怎麼證明呢 ? 可以寫兩個線程,一個使用this鎖,一個使用非靜態同步代碼塊,如果完成了同步功能,就證明非靜態同步代碼快使用的是this鎖。
     */
    public synchronized void sale() {

        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
            tickets--;
        }
    }
}

 

 

上面都是各種做鎖的例子, 這裏是創建多線程,並調用:

/**
 * @author: wangqinmin
 * @date : 2020/7/3
 * @description: 仰天大笑出門去,我輩豈是蓬蒿人
 */
public class Test {

    public static void main(String[] args) {

        TicketRunnable ticket = new TicketRunnable();

        Thread t1 = new Thread(ticket, "窗口1");
        Thread t2 = new Thread(ticket, "窗口2");

        t1.start();
        t2.start();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章