多線程基本概念


1)線程包括哪些狀態,分別是什么?

1.新建狀態(new)  :線程對象被創建后,就進入了新建狀態。例如,Thread thread = new Thread()

2.就緒狀態(Runnable):也被稱為“可執行狀態”。線程對象被創建后,其它線程調用了該對象的start()方法,從而來啟動該線程。例如,thread.start()。處於就緒狀態的線程,隨時可能被CPU調度執行

3.運行狀態(Running):線程獲取CPU權限進行執行。需要注意的是,線程只能從就緒狀態進入到運行狀態

4.阻塞狀態(Blocked)阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:
    (01) 等待阻塞 -- 通過調用線程的wait()方法,讓線程等待某工作的完成。
    (02) 同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態。
    (03) 其他阻塞 -- 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢

5.死亡狀態(dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

2)實現多線程的方式

1.繼承Thread類,重寫run()方法

Thread本質上也是實現了Runnable接口的一個實例,它代表了一個線程的實例,並且,啟動線程的唯一方法就是通過Thread類的start()方法

代碼實現:

public class MyThread extends Thread {
    private int ticket = 10;

    public void run() {
        for (int i = 0; i < 20; i++) {
            if (this.ticket > 0) {
                System.out.println(this.getName() + " 賣票:ticket" + this.ticket--);
            }
        }
    }

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        MyThread thread3 = new MyThread();
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

運行結果:

Thread-1 賣票:ticket10
Thread-1 賣票:ticket9
Thread-1 賣票:ticket8
Thread-1 賣票:ticket7
Thread-1 賣票:ticket6
Thread-1 賣票:ticket5
Thread-1 賣票:ticket4
Thread-1 賣票:ticket3
Thread-1 賣票:ticket2
Thread-1 賣票:ticket1
Thread-0 賣票:ticket10
Thread-0 賣票:ticket9
Thread-0 賣票:ticket8
Thread-0 賣票:ticket7
Thread-2 賣票:ticket10
Thread-0 賣票:ticket6
Thread-2 賣票:ticket9
Thread-2 賣票:ticket8
Thread-2 賣票:ticket7
Thread-2 賣票:ticket6
Thread-2 賣票:ticket5
Thread-2 賣票:ticket4
Thread-2 賣票:ticket3
Thread-2 賣票:ticket2
Thread-2 賣票:ticket1
Thread-0 賣票:ticket5
Thread-0 賣票:ticket4
Thread-0 賣票:ticket3
Thread-0 賣票:ticket2
Thread-0 賣票:ticket1

 

2.實現Runnable接口,並實現run()方法

以下是主要步驟:

1)自定義類並實現Runnable接口,實現run()方法。

2)創建Thread對象,用實現Runnable接口的對象作為參數實例化該Thread對象

3)調用Thread的start()方法

代碼實現:

public class MyThread implements Runnable {
    private int ticket = 10;

    public void run() {
        for (int i = 0; i < 20; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + " 賣票:ticket" + this.ticket--);
            }
        }
    }

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

運行結果:

Thread-0 賣票:ticket9
Thread-1 賣票:ticket10
Thread-2 賣票:ticket8
Thread-1 賣票:ticket6
Thread-0 賣票:ticket7
Thread-1 賣票:ticket4
Thread-2 賣票:ticket5
Thread-1 賣票:ticket2
Thread-0 賣票:ticket3
Thread-2 賣票:ticket1

說明:運行結果表示一共賣出了10張票,說明這三個線程共享了Runnable接口

3.實現Callable接口,重寫call()方法(這種方法不常用)

Callable接口實際是屬於Executor框架中的功能類...

 

3)run()方法和start()方法有什么區別

start()方法:作用為啟動一個線程,啟動后該線程處於就緒狀態,而非運行狀態,也就意味着這個線程可以被JVM來調度執行。

在調度過程中,JVM通過調用線程類的run()方法來完成實際的操作,當run()方法結束后,線程就會終止。

run()方法:如果直接調用線程類的run()方法,會被當做一個普通函數調用,程序中仍然只有主線程這一個線程,並不會產生新的線程

總的來說:start()方法能夠異步地調用run()方法,但是直接調用run()方法卻是同步的,無法達到多線程的目的

代碼示例:

public class ThreadDemo extends Thread{
    @Override
    public void run() {
        System.out.println("ThreadDemo:begin");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ThreadDemo:end");
    }
}
public class StartAndRunTest {
    /*
    test1調用start()方法
     */
    public static void test1(){
        System.out.println("test1:begin");
        Thread t1=new ThreadDemo();
        t1.start();
        System.out.println("test1:end");
    }

    /*
    test2調用run()方法
     */
    public static void test2(){
        System.out.println("test2:begin");
        Thread t1=new ThreadDemo();
        t1.run();
        System.out.println("test2:end");
    }

    public static void main(String[] args) {
        test1();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println();
        test2();
    }
}

運行結果:

從test1的運行結果來看,線程t1是在test1方法結束后才執行的,不需要等待t1,start()運行結束后(

 System.out.println("ThreadDemo:end")

)就可以執行,說明在test1中調用start()是新開啟了一個線程,main線程和t1線程是異步執行的

從test2的執行結果來看,調用t1.run()是同步的調用,語句System.out.println("ThreadDemo:end")必須等t1.run()方法調用結束后

才能 執行

 4)sleep()方法與wait()方法的區別

1.原理不同。sleep()方法是Thread類的靜態方法,是線程用來控制自身流程的,它會使此線程暫停執行一段時間,而把執行機會讓給

其他線程,等到計時時間一到,此線程會自動“蘇醒”。

wait()方法是Object類的方法,用於線程間的通信,這個方法會使當前擁有該對象鎖的進程等待,wait()使用notify或者notifyAlll或者指定睡眠時間來喚醒當前的線程。

2.對鎖的處理機制不同。調用sleep()方法不會釋放鎖,而調用wait()方法會釋放它所占用的鎖,從而使線程所在對象中的其他synchronized數據可被別的線程使用。

3.使用區域不同。由於wait()方法的特殊意義,因此它必須放在同步控制方法或者同步語句塊中使用,而sleep()方法則可以放在任何地方使用

還有就是sleep()方法必須捕獲異常,而wait()方法不需要

 

 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM