線程一些小知識的整理。
一:設置線程的優先級
需求: 定義兩個線程,對線程的優先級別進行設置,並運行!
技能: 引入線程的控制方法--- setPrirority(int i) getPrirority();
1.設計線程的優先級別的方法
1.1 public final void setPriority(int newPriority)
注意: 被final修飾的方法,只能被繼承不能被重寫!(也可以重載)
參數---int newPriority 1 5 10
在Thread當中,存在以下幾個常量:
線程可以具有的最高優先級。
public static final int MAX_PRIORITY 10
分配給線程的默認優先級。
public static final int NORM_PRIORITY 5
線程可以具有的最低優先級。
public static final int MIN_PRIORITY 1
問題: 能否直接寫整數常量? 可以的
問題: 寫入負整數以及0會出現什麼情況? 輸入的是7或8這些會出現什麼情況?
推薦怎麼傳入實參?
1.輸入負數,雖然符合int 的取值範圍,但是在後臺運行時,出現非法參數異常---IllegalArgumentException
2.發現:優先級別的範圍: 1--10之內的,包括1也包括10
3.以後在輸入實參時,建議使用Thread類噹噹中的常量
Thread.MAX_PRIRORITY Thread.MIN_PRIRORITY Thread.NORE_PRIRORITY
1.2 public final int getPriority()
發現:返回值類型是int類型 傳入的是什麼優先級,返回的就是多少。
2.由於線程具有併發性以及隨機性,即使設置的某個線程的優先級別最高,也不一定先執行!
原因: ① 隨機性
② 每一個線程都會循環得到自己的時間片,都會搶CPU資源,誰搶到了誰先運行!
既然不能保證線程優先執行,爲什麼還要進行設置?
原因:雖然不能保證優先界別最高的線程先執行,但是他優先執行的概率是很大的!
3.main方法也是屬於線程,它的優先級別是默認的,也就是5
代碼區:
public class TestPriroprity {
public static void main(String[] args) {
//1.創建Runnable接口對象
Runnable r1 = new Tiger();
Runnable r2 = new Cat();
//2.藉助Thread類,創建線程對象
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
//線程的優先級
// t1.setPriority(Thread.MAX_PRIORITY);
// t2.setPriority(Thread.MIN_PRIORITY);
t1.setPriority(7);
t2.setPriority(8);
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
//獲取main方法也就是主線程的名稱和優先級別
System.out.println(Thread.currentThread().getName());
int pri=Thread.currentThread().getPriority();
System.out.println("pri="+pri);
//3.啓動線程
t1.start();
t2.start();
}
}
class Tiger implements Runnable{
@Override
public void run() {
System.out.println("Tiger線程優先級別是最高級---MAX_PRIRORITY");
}
}
class Cat implements Runnable{
@Override
public void run() {
System.out.println("Tiger線程優先級別是最低級---MIN_PRIRORITY");
}
}
二:線程的強制加入
需求: 在你做一件好事的時候,即將完成,突然---半路殺出個程咬金
技能: 線程控制方法----強制加入
1.強制加入的方法---join();
public final void join() throws InterruptedException
發現: 使用final修飾以及拋出了異常(中斷異常)
2.時時刻刻要記住----main方法也是一個線程
3.思路步驟:
3.1 先創建一個線程類(創建線程對象),最好實現Runnable接口
3.2 重寫run()方法,在run()方法內部,定義一個for循環(有限循環)
3.3 在main方法當中,定義一個for循環---循環次數20次,當循環到10次的時候,另外一個線程強制加入!
發現:只有強制加入的線程執行完畢之後,其他的線程才能繼續運行,反之,其他線程不能執行!
代碼區:
public class TestJoinThread {
//主方法也是一個線程
public static void main(String[] args) {
//創建ChengYaoJin線程對象
Runnable r = new ChengYaoJin();
Thread t = new Thread(r);
for(int i=1;i<=20;i++){
System.out.println("牛榮君超級大美女-----自戀"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//當循環到第10次的時候,闞天陽來了....
if(i==10){
//啓動線程
t.start();
//強制加入,由於此方法拋出異常,所以在調用時必須對異常進行處理----try catch捕捉異常
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class ChengYaoJin implements Runnable{
//重寫接口當中的run()方法
public void run() {
//因爲run方法是線程的主體,所以要把核心代碼放入到此方法中
for(int i=1;i<=10;i++){
System.out.println("誰拿走了我的八塊腹肌----闞天陽"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
三:線程休眠:
需求1: 運動會---裁判 預備 1 2 3 開始
技能1: 引入線程的控制方法---線程休眠
需求2: 定義一個時間,時間的格式: HH:mm:ss,每隔一秒進行打印一次!
技能2: 引入線程的控制方法---線程休眠
1.線程休眠的方法
public static void sleep(long millis)throws InterruptedException
發現: 此方法使用static修飾,所以可以使用類名稱直接調用。此方法拋出異常,所以在調用時必須處理異常---捕捉異常。
2.此方法的作用
2.1 線程進行堵塞狀態,休眠時間結束,會在次進入就緒狀態,參與分配CPU資源,運行線程!
2.2 可以被變相的看成是一個轉換器---例如: 兩個線程交叉運行 線程A運行一次,線程B運行一次,以此類推
體現: 在定義兩個線程時,在run方法當中,插入線程休眠的方法,具體看實例!
如果想具體的保證兩個線程的交叉允許,可以使用同步鎖完成!
3.方法的參數
long millis --- 毫秒數 單位的換算 1000毫米=1秒
代碼區:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleepThread {
public static void main(String[] args) {
//1.時間格式化類---DateFormat SimpleDateFormat()
DateFormat df = new SimpleDateFormat("HH:mm:ss");
//2.定義while循環,目的: 打印時間
while(true){
//打印時間,必須有一個Date類對象
Date d = new Date();
//DateFormat類存在一個format(Date d) 返回值是String類型
String now=df.format(d);
System.out.println(now);
//每隔一秒進行打印輸出時間
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void show(){
//1.裁判應該先喊: 各就各位 預備
System.out.println("各就各位 預備..............");
//2.等待三秒,三秒已過,立即開始執行....
for (int i = 1; i < 4; i++) {
System.out.println(i);
//每一次輸出i的值,需要間隔一秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//3.開始
System.out.println("開始....................");
}
}
四:線程的禮讓
需求: 古裝劇------西門大官人 林娘子 潘娘子, 定義兩個線程,每一個線程要交叉運行,一個線程喊: 官人 一個線程喊: 娘子
技能: 線程禮讓的方法----yield();
1.線程禮讓----yield方法
暫停當前正在執行的線程對象,並執行其他線程。
public static void yield()
發現: 此方法沒有拋出異常,同時使用static修飾,所以類名稱可以直接調用!
特點: 暫停正在執行的線程,讓其他線程先執行,而且此方法不是阻塞線程,而是將線程轉入---就緒狀態,不是阻塞狀態
continue --- 結束本次循環,執行下一次循環
yield() --- 讓出當前的CPU資源,讓其他的線程優先執行!
2.線程要交叉運行--- 解決方案
2.1 使用的是線程的休眠---發現: 並不一定按照交叉運行,可能是某一個線程執行完畢,另外一個線程才執行。
2.2 使用線程的禮讓,但是呢,它也不能保證線程的交叉運行,只是一定程度上,可以實現,如果想線程之間真正的交叉允許,需要使用線程同步。
3.步驟:
3.1 創建線程---一個線程充當: 男友 -- 官人
一個線程充當: 女友 -- 娘子
實現的方式: 先通過繼承的方式,在使用實現Runnable接口的方式
3.2 要重寫run()方法---不管是繼承Thread類也好,還是實現Runnable接口也好,都要重寫run()方法
原因: 因爲run()方法,是線程的主體,核心代碼放入到此方法中。
3.3 在重寫的過程當中,可以使用線程休眠也可以使用線程禮讓
3.4 在main方法當中,創建線程,並啓動線程!
public class TestYieldThread {
public static void main(String[] args) {
//1.創建線程對象
Thread t1 = new GuanRen();
Thread t2 = new NiangZi();
//2.爲線程命名
t1.setName("\t潘娘子");
t2.setName("西門大官人");
//3.啓動線程
t1.start();
t2.start();
}
}
//創建線程類,通過繼承Thread類實現
class GuanRen extends Thread{
//重寫run()方法
public void run(){
//for循環語句 目的: 爲了實現交叉運行,肯定有一個定喊話次數
for(int i=1;i<=10;i++){
System.out.println(this.getName()+"喊:官人.....");
//切換 -- sleep();
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//線程的禮讓
Thread.yield();
}
}
}
class NiangZi extends Thread{
//重寫run()方法
public void run(){
//for循環語句 目的: 爲了實現交叉運行,肯定有一個定喊話次數
for(int i=1;i<=10;i++){
System.out.println(this.getName()+"喊:娘子.....");
//切換 -- sleep();
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//線程的禮讓
Thread.yield();
}
}
}
五:設置線程爲後臺線程
需求: 在main方法當中,創建線程,並設置線程爲後臺線程,main方法運行結束之後,後臺線程也隨之結束!
技能: 線程的控制方法-----後臺線程。
1.設置線程爲後臺線程
public final void setDaemon(boolean on)
將該線程標記爲守護線程或用戶線程
發現:1.此方法使用final修飾 2. 沒有拋出異常 3. 參數類型是布爾值,如果是true則設置爲後臺線程,反之,是前臺線程。
2.後臺線程---前臺線程
後臺線程又被稱爲守護線程,前臺線程又被稱爲用戶線程!
注意: 咱們一般創建的線程都是用戶線程,特別說明: main方法時一個用戶線程
後臺線程----最典型的例子就是GC---垃圾回收器
3.設置線程爲後臺線程,必須是在線程的啓動之前,也就是start()方法之前進行設置!
代碼區:
public class TestSetDeamonThread {
//主方法不僅是一個線程,還是一個用戶線程(前臺線程)
public static void main(String[] args) {
//1.創建線程對象
Runnable r = new QianJinHui(); //目的: 爲Thread類創建對象,做準備
Thread t = new Thread(r); //根據構造方法,傳入Runnable接口對象
//2.設置後臺線程
t.setDaemon(true);
//3.啓動線程
t.start();
//4.也寫一個for循環,for循環執行結束,後臺線程也隨之結束,即使後臺線程中的run方法嵌套了一個死循環,也要結束
for(int i=1;i<=5;i++){
System.out.println("週日計劃----休眠"+i);
}
}
}
//創建一個線程類
class QianJinHui implements Runnable{
//重寫run()方法
public void run() {
//爲了體現出: 前臺線程結束之後,後臺線程也隨之結束,寫一個死循環
while(true){
System.out.println("上課玩手機,該罰-----十個俯臥撐!");
}
}
}
原博地址(也是我,O(∩_∩)O哈哈~):http://m15231417197.lofter.com/
練習代碼地址(嘿嘿嘿):https://download.csdn.net/download/m15231417197/10716486