Java多線程2 線程創建的兩種方式與Thread類常用方法

/*
線程的創建方式

一 Java語言的JVM允許程序運行多個線程,它通過java.lang.Thread類來體現。
Thread類的特性
1,每個線程都是通過某個特定Thread對象的run()方法來完成操作的,經常
把run()方法的主體稱爲線程體
2,通過該Thread對象的start()方法來啓動這個線程,而非直接調用run()
3,構造器
*Thread():創建新的Thread對象
*Thread(String threadname):創建線程並指定線程實例名
*Thread(Runnable target):指定創建線程的目標對象,它實現了Runnable接口中的run方法
*Thread(Runnable target, String name):創建新的Thread對象
4,常用方法
*void start(): 啓動線程,並執行對象的run()方法
*void run(): 線程在被調度時執行的操作
*String getName(): 返回線程的名稱
*void setName(String name):設置該線程名稱,也可以通過構造器命名
*static Thread currentThread(): 返回當前線程。在Thread子類中就是this,通常用於主線程和Runnable實現類
*static void yield():線程讓步,主動釋放當前線程的cpu資源,但下一步cpu如何分配無法確定。
1暫停當前正在執行的線程,把執行機會讓給優先級相同或更高的線程
2若隊列中沒有同優先級的線程,忽略此方法
*join() :當某個程序執行流中調用其他線程的 join() 方法時,調用線程將
被阻塞,直到 join() 方法加入的 join 線程執行完爲止,低優先級的線程也可以獲得執行
*static void sleep(long millis):(指定時間:毫秒)
1令當前活動線程在指定時間段內放棄對CPU控制,使其他線程有機會被執行,時間到後重排隊。
2拋出InterruptedException異常
*stop(): 強制線程生命期結束,不推薦使用
*boolean isAlive():返回boolean,判斷線程是否還活着
使用注意:

  1. 如果自己手動調用run()方法,那麼就只是普通方法,沒有啓動多線程模式。
  2. run()方法由JVM調用,什麼時候調用,執行的過程控制都有操作系統的CPU調度決定。
  3. 想要啓動多線程,必須調用start方法。
  4. 一個線程對象只能調用一次start()方法啓動,如果重複調用了,則將拋出以上的異常“IllegalThreadStateException”。
    5,yield()方法下一步執行哪個線程看概率,sleep()方法會使線程在之後確定的時間段內被阻塞,之後重新排隊
    join()方法會使當前線程被阻塞到插入的線程執行完畢後纔會被執行。
    6.join()方法與sleep()方法都需要處理異常。
    7,Thread的匿名子類無法調用join方法,因爲需要先調用一次start()方法啓動線程才能加入其他線程中。

二 Java中線程的調度方法
1同優先級線程組成先進先出隊列(先到先服務),使用時間片策略
2對高優先級,使用優先調度的搶佔式策略

線程的優先級等級
thread類中的常量,可以直接調用
MAX_PRIORITY:10 最大
MIN _PRIORITY:1 最小
NORM_PRIORITY:5 默認

涉及的方法
getPriority() :返回線程優先值
setPriority(int newPriority) :改變線程的優先級,範圍1-10

說明
線程創建時繼承父線程的優先級,未設置情況下默認優先級是5.
低優先級只是獲得調度的概率低,並非一定是在高優先級線程之後才被調用

三創建線程的方式
JDK1.5之前創建新執行線程有兩種方法:
*繼承Thread類的方式
*實現Runnable接口的方式

方式一:繼承Thread類
1 定義子類繼承Thread類。
2 子類中重寫Thread類中的run方法。
3 創建Thread子類對象,即創建了線程對象。
4 調用線程對象start方法:啓動線程,調用run方法。

方式二:實現Runnable接口
1 定義子類,實現Runnable接口。
2 子類中重寫Runnable接口中的run方法。
3 通過Thread類含參構造器創建線程對象。
4 將Runnable接口的子類對象作爲實際參數傳遞給Thread類的構造器中。
5 調用Thread類的start方法:開啓線程,Thread類中的run()方法調用的是Runnable接口實現類的run方法。

繼承方式和實現方式的聯繫與區別
區別
*繼承Thread:線程代碼存放Thread子類run方法中。
*實現Runnable:線程代碼存在接口的子類的run方法。
實現方式的好處
*避免了單繼承的侷限性
*多個線程可以共享同一個接口實現類的對象,非常適合多個相同線程來處理同一份資源。

*/

package leanthread;

import com.sun.jmx.snmp.SnmpUnknownAccContrModelException;

import javax.xml.namespace.QName;

/**
 * @Description:
 * @Version:1.0.0.1
 * @Date:2020--03--03--22:07
 * @Author:wisdomcodeinside
 * @E-mail:[email protected]
 */
public class ThreadTest2 {
    public static void main(String[] args) {
        OddThread o = new OddThread();//主線程創建對象
        o.start();//start()方法開始創建分支線程,然後調用當前線程的run()方法,方法體是重寫的方法體
//      o.run();//此時只是在主線程中執行對象的run()方法,不是在分支線程中運行。
//      o.start();//會報IllegalThreadStateException異常,同一個線程子類的對象不能啓動兩次。
        OddThread o1 = new OddThread("無名");
        o1.start();//新對象可以啓動新線程
        Thread.currentThread().setName("老大哥");//可以對主線程命名
        Thread.currentThread().setPriority(10);//可以設置主線程優先級
        //主線程輸出方法
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "主線任務"
                    + "任務等級" + Thread.currentThread().getPriority() + "完成次數" + i);//主線程與分支線程的輸出會交錯顯示。
            if (i == 49) {
                try {
//                    new Thread(){
//                        @Override
//                        public void run() {
//                            for (int j = 0; j < 10; j++) {
//                                System.out.println("奇遇任務" + j);
//                            }
//                        }
//                    }//匿名子類無法start()
                    o1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //對於只使用一次的線程可以使用匿名子類的方式
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "\t無心");
                    if (i % 2 == 0) {
                        this.yield();
                        try {
                            sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "\t法師");
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        //倒計時
        new Thread() {
            @Override
            public void run() {
                System.out.println("您的GTX690即將啓動");
                for (int i =10; i > 0; i--) {
                    System.out.println(i);
                    try {
                        sleep(1000);//1000毫秒爲1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Fallout");
            }
        }.start();
        //查看線程狀態
        System.out.println(o.isAlive());
        System.out.println(o1.isAlive());
        System.out.println(Thread.currentThread().isAlive());
        //測試買票線程
        SellTicketWindow window1 = new SellTicketWindow("窗口1");
        SellTicketWindow window2 = new SellTicketWindow("窗口2");
        SellTicketWindow window3 = new SellTicketWindow("窗口3");
        window1.start();
        window2.start();
        window3.start();
        //測試買票線程
        TicketWindow t = new TicketWindow();
        Thread ticketWindow1 = new Thread(t);
        Thread ticketWindow2 = new Thread(t);
        Thread ticketWindow3 = new Thread(t);
        ticketWindow1.setName("賣票窗口1");
        ticketWindow1.start();
        ticketWindow2.setName("賣票窗口2");
        ticketWindow2.start();
        ticketWindow3.setName("賣票窗口3");
        ticketWindow3.start();
    }
}

class OddThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + "支線任務"
                        + "任務等級" + Thread.currentThread().getPriority() + "完成次數" + i);//獲取當前線程的名字
            }
        }
    }

    public OddThread(String name) {
        super(name);
    }

    public OddThread() {
        super();
    }
}
//繼承Thread類來創建線程
class SellTicketWindow extends Thread{
    private static int ticket = 100;//ticket是線程共用的屬性,必須聲明爲static的,或者類繼承Runnable接口
    private int total = 0;
    @Override
    public void run() {
        while (true) {
            if(ticket > 0){
                System.out.println(getName() + "賣出一張票," + "票號爲:" + ticket);
                ticket--;
                total++;
            }else{
                System.out.println("票已賣完,謝謝關照");
                System.out.println(Thread.currentThread().getName() + "總共賣出" + total + "張票");
                break;
            }
        }
    }
    public SellTicketWindow(String name){
        super(name);
    }
}
//實現Runnable接口來創建線程
class TicketWindow implements Runnable {
    private int ticket = 100;//線程共用一個對象,不用加上static
    @Override
    public void run() {
        while (true) {
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName() + "賣出一張票," + "票號爲:" + ticket);
                ticket--;
            }else{
                System.out.println("票已賣完,謝謝關照");
                break;
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章