Java多線程Thread類的使用詳解
1.創(chuàng)建一個線程
Java操作線程最核心的類就是Thread類
創(chuàng)建線程有很多方法,下面我們寫一個Mythread類繼承 Thread 類重寫run()方法來創(chuàng)建線程
package thread;
class MyThread extends Thread{
public void run(){
System.out.println("hello world!");
}
}
public class ThreaDemo1 {
public static void main(String[] args) {
Thread t = new MyThread();
}
}這里的Thread類不需要import包,是因為這個類和String,StringBuffer這些類一樣是在java.lang包中,已經(jīng)自動導入了!
run()方法是重寫了Thread類的run()方法,重寫就是和父類方法名參數(shù)都相同,子類的方法通過動態(tài)綁定機制被調(diào)用
就像上面的:
Thread t = new MyThread(); t.run();
這里的t是父類的引用,調(diào)用的run()仍然是子類的方法,本質上t還是指向子類對象
重載是同一個作用域,多個方法的方法名相同,參數(shù)個數(shù)或類型不同的方法
2.start()方法與run()方法
我們用t調(diào)用一個strat方法
public class ThreaDemo1 {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
}
}
這里的hello world和我們直接在打印出來的hello world是不同的!!!
這里的是由t.start()創(chuàng)建了一個新的線程,然后由線程負責執(zhí)行t.run(),打印出hello world!
t.start()創(chuàng)建新的線程時,調(diào)用了操作系統(tǒng)的API,通過操作系統(tǒng)內(nèi)核創(chuàng)建新線程的PCB,并把要執(zhí)行的指令交給這個PCB,當PCB被調(diào)度到CPU上執(zhí)行的時候,就能執(zhí)行到run()方法中的代碼了
直接打印hello world時,java進程就只有一個線程(就是調(diào)用main方法的線程)也就是主線程
通過t.start(),主線程調(diào)用了t.start(),t.start()創(chuàng)建出新的線程,新的線程調(diào)用t.run();
當run()方法執(zhí)行完畢,新的的線程就自動銷毀
創(chuàng)建線程歸結到底還是要解決并發(fā)編程問題,我們來看一個并發(fā)的例子
class MyThread extends Thread{
public void run(){
while(true){
System.out.println("hello world!");
//休眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class ThreaDemo1 {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
while(true){
System.out.println("hello main!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}這段代碼并不是只執(zhí)行到一個循環(huán),死循環(huán)出不來了,而是交替執(zhí)行的

這就是并發(fā)執(zhí)行的效果,執(zhí)行的順序也是不確定的,主要原因是:操作系統(tǒng)調(diào)度線程的時候是"搶占式執(zhí)行",具體哪個線程先執(zhí)行,哪個線程后執(zhí)行,都是不確定的,取決于操作系統(tǒng)調(diào)度策略
雖然也是有優(yōu)先級的,但是從應用程序方面來看到的效果是隨機的,我們在程序上無法修改的
如果我們只執(zhí)行t.run()會是什么情況呢?
public static void main(String[ ] args)l
Thread t = new MyThread(;
t.run();
while(true){
system.out.println("hello main! ");
try {
Thread.sleep( millis: 1000) ;
catch (InterruptedException e) {
throw new RuntimeException(e);
}結果

這里只執(zhí)行了run方法,沒有執(zhí)行hellomain這里,是因為只有一個主線程是單線程工作的
不會交替執(zhí)行,這就是單線程和多線程的差異
run()和start()的區(qū)別
run是線程里的方法,描述的是線程要執(zhí)行的任務,但是線程還沒有執(zhí)行,只有調(diào)用start后,線程才會開始運行,調(diào)用后會申請線程并執(zhí)行run方法,執(zhí)行完后進入銷毀線程階段,也就是說strat才是真正創(chuàng)建了線程,并且線程是獨立的執(zhí)行流
3.查看線程
我們可以使用jdk自帶的工具jconsole查看當前的java進程中的所有線程
這個工具一般路徑:C:\Program Files\Java\jdk1.8.0_192\bin

雙擊打開運行會看到本地進程

接下來點擊一下我們運行的程序的線程


點擊線程

可以看到有很多線程

詳細信息


其它的線程都是JVM自帶的線程
注意:如果打開工具本地進程什么也沒有,可以嘗試用右鍵,管理員方式運行
new Thread 對象時,不創(chuàng)建線程,調(diào)用start才是創(chuàng)建PCB才有真實的線程
主線程調(diào)用就是start方法寫到main方法中被調(diào)用
4.創(chuàng)建線程的各種方法
Java中創(chuàng)建線程的方法有很多種,上面使用的就是繼承Thread類,重寫run()方法的方法,下面了解一下其他三種方法
4.1實現(xiàn)Runnable接口
回顧:
抽象類和普通類的區(qū)別:抽象類不能實例化,不能直接new,必須有子類繼承抽象類,然后抽象類中有抽象方法,抽象方法沒有方法體,需要子類重寫抽象方法
接口比抽象類更進一步,抽象類除抽象方法之外還有普通方法和屬性,接口則是只有抽象方法
class MyRunnable implements Runnable{
public void run(){
System.out.println("hello thread!");
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
}
}Runnable是描述任務,具體執(zhí)行細節(jié)就是run()方法,任務還要交給線程來執(zhí)行

使用Runnable接口達到了解耦合的目的,將線程和線程的任務分開,如果要修改代碼,代碼改動就比較小
4.2使用匿名內(nèi)部類
public class ThreadDemo3 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
System.out.println("hello world!");
}
};
t.start();
}
}這里創(chuàng)建了一個Thread的子類,子類是匿名的,還創(chuàng)建了子類的實例,并且讓t指向實例

4.3使用匿名內(nèi)部類實現(xiàn)Runnable
public class ThreadDemo4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world!!");
}
});
t.start();
}
}寫法和1本質相同,只不過把實現(xiàn)Runnable 任務交給匿名內(nèi)部類的語法,此處是創(chuàng)建了一個類,實現(xiàn)Runnable,同時創(chuàng)建了實例,并且把實例傳給Thread的構造方法(匿名內(nèi)部類的創(chuàng)建的實例作為Thread的構造方法參數(shù))
4.4使用Lambda表達式
這是比較簡單的,推薦的寫法
public class ThreadDemo5 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello world!!");
});
t.start();
}
}把任務通過Lambda表達式來描述,直接把Lambda表達式傳給Thread的構造方法

到此這篇關于Java多線程Thread類的使用詳解的文章就介紹到這了,更多相關Java多線程Thread內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
idea配置Tomcat時沒有Artifacts選項的解決方法
本文主要介紹了idea配置Tomcat時沒有Artifacts選項的解決方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05
詳解如何使用Jersey客戶端請求Spring Boot(RESTFul)服務
本篇文章主要介紹了詳解如何使用Jersey客戶端請求Spring Boot(RESTFul)服務,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
配置pom.xml用maven打包java工程的方法(推薦)
下面小編就為大家?guī)硪黄渲胮om.xml用maven打包java工程的方法(推薦)。小編覺得挺不錯的, 現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06

