線程及synchronized鎖的理解

程序、進程與線程

一:概念理解
 

程序:靜態的代碼,應用軟件執行的藍本
進程:程序的一次動態執行過程,對應了從代碼加載、執行至執行完畢的一個完整過程。
線程:比進程更小的執行單位,一個進程在執行過程中可以產生多個線程。

 
       操作系統中使用分時管理各個進程,按時間片輪流執行每個進程。Java 的多線程就是在操作系統每次分時給 Java 程序一個時間片的 CPU 時間內,在若干獨立的可控制的線程之間進行切換。
 
       Java 程序從 main 方法開始執行,當 JVM 加載代碼,發現 main 方法之後會啓動一個線程,這個線程是主線程,在 main 方法執行的過程中啓動的線程稱爲該程序的其他線程。當發現程序中包含主線程和其他線程時,JVM 會在主線程和其他線程之間輪流切換,保證每個線程都有機會使用 CPU 資源。
 
二:代碼分析
 

/**
 * 分析程序:
 *  1. JVM 首先將 CPU 資源分配給主線程,主線程在分配時執行了:
 *      //創建線程
 *      SpeakHello speakHello = new SpeakHello();
 *      SpeakNiHao speakNiHao = new SpeakNiHao();
 *      //啓動線程
 *      speakHello.start();
 *      speakNiHao.start();
 *  2. 開始執行 for 循環,for 循環爲啥沒執行完呢?
 *      主線程在使用 CPU 資源的時候執行了:
 *          speakHello.start();
 *          speakNiHao.start();
 *      所以 JVM 知道已經有三個線程需要輪流切換使用 CPU 資源
 *  3. speakNiHao.start() 的作用是通知 JVM: 咳咳咳,老子在等着你給我分配 CPU 資源
 * @author guozhenZhao
 * @date 2018年12月22日
 */
public class ThreadTest {
    //主程序(主線程)
    public static void main(String[] args) {
        //創建線程
        SpeakHello speakHello = new SpeakHello();
        SpeakNiHao speakNiHao = new SpeakNiHao();
        //啓動線程
        speakHello.start();
        speakNiHao.start();

        for (int i = 1; i <= 20; i++) {
            System.out.print("大家好"+i+" ");
        }
    }
}

//線程一
class SpeakHello extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.print("hello"+i+" ");
        }
    }
}

//線程二
class SpeakNiHao extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.print("您好"+i+" ");
        }
    }

}

synchronized關鍵字的理解

 

package com.zgz.multi.sync001;

/**
 * 兩種情況:
 * 一:
 *  關鍵字synchronized取得的鎖都是對象鎖,而不是把一段代碼(方法)當作鎖
 *  所以代碼中那個線程先執行synchronized關鍵字的方法,哪個線程就持有該方法所屬對象的鎖(lock)
 * 二:
 *  在靜態方法上加synchronized關鍵字,表示鎖定.class類,類一級別的鎖(獨佔這個類)
 * @author guozhenZhao
 * @date 2018年12月22日
 */
public class MultiThread {
    private static int num = 0;

    public synchronized void printNum(String tag) {
        try {
            if(tag.equals("a")) {
                num = 100;
                System.out.println("tag a, set num over");
                Thread.sleep(1000);
            }else {
                num = 200;
                System.out.println("tag b, set num over");
            }

            System.out.println("tag: "+tag+", num=" + num);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //注意觀察run方法輸出順序
    public static void main(String[] args) {
        //兩個不同的對象
        final MultiThread m1 = new MultiThread();
        final MultiThread m2 = new MultiThread();

        //創建線程t1、t2
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                m1.printNum("a");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                m2.printNum("b");
            }
        });

        //通知jvm,有線程在等待執行
        t1.start();
        t2.start();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章