Process與Thread
◆線程就是獨立的執行路徑;
◆在程序運行時,即使沒有自己創建線程,後臺也會有多個線程,如主線程,gc線程
◆main()稱之爲主線程,爲系統的入口,用於執行整個程序; .
◆在一個進程中,如果開闢了多個線程,線程的運行由調度器安排調度,調度器是與
操作系統緊密相關的,先後順序是不能認爲的干預的。
◆對同一份資源操作時,會存在資源搶奪的問題,需要加入併發控制;
◆線程會帶來額外的開銷,如cpu調度時間,併發控制開銷。
◆每個線程在自己的工作內存交互,內存控制不當會造成數據不一致
Java多線程
-
程序、進程、線程的概念
-
Java中多線程的創建和使用
- 繼承Thread類與實現Runnable接口
- Thread類的主要方法
- 線程的調度與設置優先級周
-
線程的生命週期
-
線程的同步
-
線程的通信
一、基本概念
程序-進程-線程
- 程序(program)是爲完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼,靜態對象。
- 進程(process)是程序的一次執行過程,或是正在運行的一個程序。動態過程:有它自身的產生存在和消亡的過程。
- 如:運行中的QQ,運行中的MP3播放器
- 程序是靜態的,進程是動態的
- 線程(thread),進程可進一步細化爲線程,是一個程序內部的一條執行路徑
- 若一個程序 可同一時間執行多個線程,就是支持多線程的
二、多線程的創建和啓動
//創建多線程的第一種方式:一.繼承java.lang.Thread類
- Java語言的JVM允許程序運行多個線程,它通過java.lang.Thread類來實現。
- Thread類的特性
- 每個線程都是通過某個特定Thread對象的run()方法來完成操作的,經常把run()方法的主體稱爲線程體
- 通過Thread對象的start()方法來調用這個線程
package Thread01;
//創建一個子線程,完成1-100自然數的輸出。同樣的,主線程執行同樣的操作
//創建多線程的第一種方式:一.繼承java.lang.Thread類
//1.創建一個繼承於Thread的子類
class SubThread extends Thread{
//2.重寫Thread類的run()方法,方法內實現此子線程要完成的功能
@Override
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class TestThread {
public static void main(String[] args) {
//3.創建一個子類對象
SubThread subThread1 = new SubThread();
SubThread subThread2 = new SubThread();
//4.調用線程的start()方法,啓動此線程:調用相應的run()方法
subThread1.start();
subThread2.start();
// subThread.start();
// 一個線程只能執行一次start()
// subThread.run();
// 不能通過Thread實現類對象run()去啓動一個線程
for (int i = 1; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
三、線程的調度
-
調度策略
- 時間片
- 搶佔式:高優先級的線程搶佔CPU
-
Java的調度方法
- 同優先級線程組成先進先出隊列(先來先服務),使用時間片策略
- 對高優先級,使用優先調度的搶佔式策略
-
線程的優先級控制
- MAX_PRIORITY(10);
- MIN_PRIORITY(1);
- NORM_PRIORITY(5);
- 涉及的方法
- getPriority():返回線程優先值
- setPriority(int newPriority):改變線程的優先級
- 線程創建時繼承父線程的優先級
package Thread02;
/*
* Thread常用方法
* 1.start(),啓動線程並執行相應的run()方法
* 2.run():子線程要執行的代碼放入run()方法中
* 3.currentThread(),靜態的,調取當前的線程
* 4.getName():獲取此線程的名字
* 5.setName():設置此線程的名字
* 6.yield():調用此方法的線程釋放當前CPU的執行權
* 7.join():在A線程中調用B線程的join方法.表示,
* 當執行到此方法,A線程停止執行,直至B線程執行完畢,
* A線程再接着join()之後的代碼執行
* 8.isAlive():判斷當前線程是否還存活
* 9.sleep(long l):顯式的讓當前線程睡眠l毫秒
* 10.線程通信:wait() notify() notifyAll()
*
* 設置線程的優先級
* - getPriority():返回線程優先值
* - setPriority(int newPriority):改變線程的優先級
* //優先級增加搶佔CPU的概率
* */
class SubThread extends Thread{
@Override
public void run() {
for (int i = 1; i <=100; i++) {
// try {
// Thread.currentThread().sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
}
}
}
public class TestThread {
public static void main(String[] args) {
SubThread subThread = new SubThread();
subThread.setName("子線程1");
// subThread.setPriority(10);
subThread.setPriority(Thread.MAX_PRIORITY);
subThread.start();
Thread.currentThread().setName("====主線程");
for (int i = 1; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
// if (i%10==0){
// Thread.currentThread().yield();
// }
// if (i==20){
// try {
// subThread.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
}
System.out.println(subThread.isAlive());
}
}
四、實現方式二
package Thread02;
/*
* //創建多線程的方式二,通過實現的方式
*
* 對比一下繼承的方式 VS 實現的方式
* 1.聯繫,public class Thread implements Runnable
* 2.哪個方式好? 實現的方式優於繼承的方式
* 爲什麼 why?
* ①避免了java單繼承的侷限性
* ②如果多線程要操作同一份資源(或數據),更適合使用實現的方式
* */
//1.創建一個實現了Runnable接口的類
class PrintNum1 implements Runnable{
//2.實現接口的抽象方法
@Override
public void run() {
//子線程執行的代碼
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class TestThread1 {
public static void main(String[] args) {
//3.創建一個Runnable接口實現類的對象
PrintNum1 printNum1 = new PrintNum1();
// printNum1.start();//無此方法
// printNum1.run();//不是多線程
//要想啓動一個多線程,必須調用start()
//4.將此對象作爲形參傳遞給Thread類的構造器中,創建Thread類的對象此對象即爲一個線程
Thread thread = new Thread(printNum1);
//5.調用start()方法,啓動線程並執行run()方法
thread.start();//啓動線程,執行Thread對象生成時構造器形參的對象的run()方法
//再創建一個線程
Thread thread1 = new Thread(printNum1);
thread1.start();
}
}
五、使用多線程的優點
- 提高應用程序的響應。對圖形化界面更有意義,可增強用戶體驗
- 提高計算機系統CPU的利用率
- 改善程序結構。將即長又複製的進程分爲多個下次,獨立運行,利於理解和修改
生命週期五種狀態:
新建:當一個Thread類或其子類的對象被聲明並創建時,新生的線程對象處於新建狀態
就緒:處於新建狀態的線程被start()後,將進入線程隊列等待CPU時間片
此時它已具備了運行條件
運行:當就緒的線程被調度並獲得處理器資源時。便進入運行狀態,run()方法定義了線程的操作和功能
阻塞:在某種特殊情況下,被人爲掛起或執行輸入輸出操作時,讓出CPU
並臨時中止自己的執行,進入阻塞狀態
死亡:線程完成了它的全部工作或線程被提前強制性地中止