/*
線程的創建方式
一 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,判斷線程是否還活着
使用注意:
- 如果自己手動調用run()方法,那麼就只是普通方法,沒有啓動多線程模式。
- run()方法由JVM調用,什麼時候調用,執行的過程控制都有操作系統的CPU調度決定。
- 想要啓動多線程,必須調用start方法。
- 一個線程對象只能調用一次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;
}
}
}
}