1. 程式人生 > >Java多執行緒1:程序與執行緒

Java多執行緒1:程序與執行緒

1.什麼是程序?

程序是作業系統結構的基礎,是一次程式的執行,是系統進行資源分配和排程的一個獨立單位。
這個解釋有點懵了。簡單來講就是一個正在作業系統中的執行的exe程式就是一個程序。

這裡寫圖片描述

2.什麼是執行緒?

執行緒可以理解為是在程序中獨立執行的子任務。比如:酷狗音樂.exe執行時,就會有很多子任務在同時執行,包括下載歌詞執行緒,直播執行緒等

3.執行緒的優點

可以在同一時間內執行更多不同種類的任務,比如作為程式設計師,我們經常邊coding,邊聽鋼琴曲,CPU在不同任務之間飛快切換,導致一種錯覺—它們是在同時執行的。

這裡寫圖片描述
這裡寫圖片描述

在單任務中,Task1需要花費100s,而Task2必須要等到Task1執行完畢後才能執行,這對Task2來說肯定很不爽,而在多工中,Task2不必等到Task1完成後再執行,它們是非同步的,因此,效率高了。

4.怎樣使用執行緒?

實現多執行緒程式設計的方式主要有2種,一種是extends Thread,一種是implements Runnable.

class MyThread extends  Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread");
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread = new
MyThread(); myThread.start(); System.out.println("結束執行"); } }

輸出:

結束執行
MyThread

extends Thread的最大弊端在於不支援多繼承,為了實現多繼承,可以使用第二種方式implements Runnable.還有,從結果上來看,run方法執行的時間較晚,也就是說,在使用多執行緒技術時,程式碼執行結果與程式碼執行順序是無關的。

這裡有一個坑就是extends Thread的執行緒多次呼叫start()方法會報
這裡寫圖片描述

這裡寫圖片描述
原因在於一個Thread例項只能啟動一個執行緒.

extends Thread 一般不太建議使用,因為單繼承原因,而更推薦implements Runnable介面。
我們先看一下Thread類的建構函式,
這裡寫圖片描述

可以看到,可以傳遞一個Runnable介面,這就好辦了,我們可以通過new Thread(Runnable target).start();的方式去啟動一個執行緒了。還有,Thread(Runnable target)不光可以接收一個Runnable介面物件,還可以接收Thread物件(因為Thread implements Runnbale了,多型嘛),這樣做完全可以將一個Thread物件的run()交給其他執行緒去呼叫
再來看一下Runnable介面有什麼方法?

這裡寫圖片描述
可以看到,就有唯一的run(),翻譯過來的意思是:”當我們implements Runnable時去建立 一個執行緒時,啟動它就會執行run()”,而通過原始碼得知Thread類其實也implements Runnable,因此我們使用run().

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("MyRunnable");
    }
}
public class Run {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        System.out.println("結束執行");
    }
}

這裡同樣多次呼叫start(),但程式是可以正常執行的。這是為什麼呢?還是剛剛說的那句話一個Thread例項只能啟動一個執行緒,這裡3次new Thread,當然不是同一個例項啦。

5.例項變數與執行緒安全

例項變數可以對其他執行緒有共享和不共享之分。

比如說,我們建立了3個執行緒,每個執行緒都有各自的count變數,它們互不影響,這就是變數不共享。
共享資料的情況就是多個執行緒同時訪問同一變數,這時往往會出現髒讀現象。
程式碼例項:

LoginServlet程式碼:

public class LoginServlet {
    private static String username;
    private static String password;
    public void dopost(String username,String password){
        LoginServlet.username = username;
        if(username.equals("a")){
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        LoginServlet.password=password;
        System.out.println("當前執行緒名稱:"+Thread.currentThread().getName()+"使用者名稱"+LoginServlet.username+"密碼"+LoginServlet.password);


    }
}

執行程式碼:

class MyThread1 extends Thread {
    LoginServlet loginServlet;

    MyThread1(LoginServlet loginServlet) {
        this.loginServlet = loginServlet;
    }

    @Override
    public void run() {
        super.run();
        loginServlet.dopost("a", "aa");
    }
}

class MyThread2 extends Thread {
    LoginServlet loginServlet;

    MyThread2(LoginServlet loginServlet) {
        this.loginServlet = loginServlet;
    }

    @Override
    public void run() {
        super.run();
        loginServlet.dopost("b", "bb");
    }
}

public class Run {
    public static void main(String[] args) {
        LoginServlet loginServlet = new LoginServlet();
        MyThread1 myThread1 = new MyThread1(loginServlet);
        MyThread2 myThread2 = new MyThread2(loginServlet);
        myThread1.start();
        myThread2.start();
    }
}

這裡寫圖片描述

這裡出現了髒讀現象,可以通過加鎖機制,關於synchronized加鎖,下次會詳細講解