1. 程式人生 > >執行緒及synchronized鎖的理解

執行緒及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();
    }
}