主線程和子線程的執行順序問題以及解決線程安全的兩種方式

主線程幾乎總是比子線程要早執行,但是多線程的執行是沒有固定順序的,誰先搶到資源就先執行誰
在虛擬機上,其實主線程mt.run()幾乎總是會比.start()調用的run()要早執行,因爲主線程Thread.start()在調用(caller)線程上創建好線程就返回了,緊接着就可以去調用執行tt.m2();而在被調用(callee)的新線程上還要經過一些JVM內部的初始化動作才能跑到指定的入口方法。

輸出結果 (一種可能)

****開始測試********
****中間分割********
****結束分隔符*******
****第一個線程********
ab
12
****第二個線程********
abcd
1234

Process finished with exit code 0

代碼

package com.atguigu.java1;

/**
 * @author liu
 * @Description
 */
public class ThreadTest1 {
    public static void main(String[] args) {

        StringBuffer s2 = new StringBuffer();
        StringBuffer s1 = new StringBuffer();

        System.out.println("****開始測試********");
        
        new Thread() {
            @Override
            public void run() {
                System.out.println("****第一個線程********");

                synchronized (s1){
                    s1.append("a");
                    s2.append("1");
                    //try是爲了測試死鎖
//                    try {
//                        Thread.sleep(100);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }

                    synchronized (s2) {
                        s1.append("b");
                        s2.append("2");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();
        //中間
        System.out.println("****中間分割********");

        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("****第二個線程********");
                synchronized (s2) {
                    s1.append("c");
                    s2.append("3");

//                    try {
//                        Thread.sleep(0);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }

                    synchronized (s1) {
                        s1.append("d");
                        s2.append("4");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
//
        System.out.println("****結束分隔符*******");
    }
    }

解決線程安全的兩種方式
方式一:同步代碼塊

synchronized(同步監視器){
//需要被同步的代碼
}
說明:1.操作共享數據的代碼,即爲需要被同步的代碼
2.共享數據:多個線程共同操作的變量,比如:ticket就是共享數據。
3.同步監視器:俗稱,鎖。任何一個類的對象,都可以充當鎖。要求,多個線程必須要共用同一個鎖。

方式二:同步方法(public synchronized void show() )

如果操作共享數據的代碼完整的聲明在一個方法中,我們不妨礙將此方法聲明在同步中。
1.同步方法仍然涉及到同步監視器,知識不需要我們顯示的聲明
2.非靜態的同步方法,同步監視器是:this
靜態的同步方法,同步監視器是:當前類本身(類.class)

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