日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java中thread实例_Java多线程2:Thread中的实例方法

發布時間:2025/3/19 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中thread实例_Java多线程2:Thread中的实例方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Thread類中的方法調用方式:

學習Thread類中的方法是學習多線程的第一步。在學習多線程之前特別提出一點,調用Thread中的方法的時候,在線程類中,有兩種方式,一定要理解這兩種方式的區別:

1、this.XXX()

這種調用方式表示的線程是線程實例本身

2、Thread.currentThread.XXX()或Thread.XXX()

上面兩種寫法是一樣的意思。這種調用方式表示的線程是正在執行Thread.currentThread.XXX()所在代碼塊的線程

當然,這么說,肯定有人不理解兩者之間的差別。沒有關系,之后會講清楚,尤其是在講Thread構造函數這塊。講解后,再回過頭來看上面2點,會加深理解。

Thread類中的實例方法

從Thread類中的實例方法和類方法的角度講解Thread中的方法,這種區分的角度也有助于理解多線程中的方法。實例方法,只和實例線程(也就是new出來的線程)本身掛鉤,和當前運行的是哪個線程無關。看下Thread類中的實例方法:

1、start()

start()方法的作用講得直白點就是通知"線程規劃器",此線程可以運行了,正在等待CPU調用線程對象得run()方法,產生一個異步執行的效果。通過start()方法產生得到結論,先看下代碼:

public class MyThread02 extends Thread

{

public void run()

{

try

{

for (int i = 0; i < 3; i++)

{

Thread.sleep((int)(Math.random() * 1000));

System.out.println("run = " + Thread.currentThread().getName());

}

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

public static void main(String[] args)

{

MyThread02 mt = new MyThread02();

mt.start();

try

{

for (int i = 0; i < 3; i++)

{

Thread.sleep((int)(Math.random() * 1000));

System.out.println("run = " + Thread.currentThread().getName());

}

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

看下運行結果:

run = Thread-0

run = main

run = main

run = main

run = Thread-0

run = Thread-0

結果表明了:CPU執行哪個線程的代碼具有不確定性。再看另外一個例子:

public class MyThread03 extends Thread

{

public void run()

{

System.out.println(Thread.currentThread().getName());

}

}

public static void main(String[] args)

{

MyThread03 mt0 = new MyThread03();

MyThread03 mt1 = new MyThread03();

MyThread03 mt2 = new MyThread03();

mt0.start();

mt1.start();

mt2.start();

}

看下運行結果:

Thread-1

Thread-2

Thread-0

盡管啟動線程是按照mt0、mt1、mt2,但是實際的啟動順序卻是Thread-1、Thread-2、Thread-0。這個例子說明了:調用start()方法的順序不代表線程啟動的順序,線程啟動順序具有不確定性。

2、run()

線程開始執行,虛擬機調用的是線程run()方法中的內容。稍微改一下之前的例子看一下:

public static void main(String[] args)

{

MyThread02 mt = new MyThread02();

mt.run();

try

{

for (int i = 0; i < 3; i++)

{

Thread.sleep((int)(Math.random() * 1000));

System.out.println("run = " + Thread.currentThread().getName());

}

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

MyThread02的代碼不變,看下運行結果:

run = main

run = main

run = main

run = main

run = main

run = main

看到打印了6次的"run = main",說明如果只有run()沒有start(),Thread實例run()方法里面的內容是沒有任何異步效果的,全部被main函數執行。換句話說,只有run()而不調用start()啟動線程是沒有任何意義的。

3、isAlive()

測試線程是否處于活動狀態,只要線程啟動且沒有終止,方法返回的就是true。看一下例子:

public class MyThread06 extends Thread

{

public void run()

{

System.out.println("run = " + this.isAlive());

}

}

public static void main(String[] args) throws Exception

{

MyThread06 mt = new MyThread06();

System.out.println("begin == " + mt.isAlive());

mt.start();

Thread.sleep(100);

System.out.println("end == " + mt.isAlive());

}

看下運行結果:

begin == false

run = true

end == false

看到在start()之前,線程的isAlive是false,start()之后就是true了。main函數中加上Thread.sleep(100)的原因是為了確保Thread06的run()方法中的代碼執行完,否則有可能end這里打印出來的是true,有興趣可以自己試驗一下。

4、getId()

這個方法比較簡單,就不寫例子了。在一個Java應用中,有一個long型的全局唯一的線程ID生成器threadSeqNumber,每new出來一個線程都會把這個自增一次,并賦予線程的tid屬性,這個是Thread自己做的,用戶無法執行一個線程的Id。

5、getName()

這個方法也比較簡單,也不寫例子了。我們new一個線程的時候,可以指定該線程的名字,也可以不指定。如果指定,那么線程的名字就是我們自己指定的,getName()返回的也是開發者指定的線程的名字;如果不指定,那么Thread中有一個int型全局唯一的線程初始號生成器threadInitNum,Java先把threadInitNum自增,然后以"Thread-threadInitNum"的方式來命名新生成的線程

6、getPriority()和setPriority(int newPriority)

這兩個方法用于獲取和設置線程的優先級,優先級高的CPU得到的CPU資源比較多,設置優先級有助于幫"線程規劃器"確定下一次選擇哪一個線程優先執行。換句話說,兩個在等待CPU的線程,優先級高的線程越容易被CU選擇執行。下面來看一下例子,并得出幾個結論:

public class MyThread09_0 extends Thread

{

public void run()

{

System.out.println("MyThread9_0 run priority = " +

this.getPriority());

}

}

public class MyThread09_1 extends Thread

{

public void run()

{

System.out.println("MyThread9_1 run priority = " +

this.getPriority());

MyThread09_0 thread = new MyThread09_0();

thread.start();

}

}

public static void main(String[] args)

{

System.out.println("main thread begin, priority = " +

Thread.currentThread().getPriority());

System.out.println("main thread end, priority = " +

Thread.currentThread().getPriority());

MyThread09_1 thread = new MyThread09_1();

thread.start();

}

看一下運行結果:

main thread begin, priority = 5

main thread end, priority = 5

MyThread9_1 run priority = 5

MyThread9_0 run priority = 5

從這個例子我們得出結論:線程默認優先級為5,如果不手動指定,那么線程優先級具有繼承性,比如線程A啟動線程B,那么線程B的優先級和線程A的優先級相同。下面的例子演示了設置線程優先級帶來的效果:

public class MyThread10_0 extends Thread

{

public void run()

{

long beginTime = System.currentTimeMillis();

for (int j = 0; j < 100000; j++){}

long endTime = System.currentTimeMillis();

System.out.println("◆◆◆◆◆ thread0 use time = " +

(endTime - beginTime));

}

}

public class MyThread10_1 extends Thread

{

public void run()

{

long beginTime = System.currentTimeMillis();

for (int j = 0; j < 100000; j++){}

long endTime = System.currentTimeMillis();

System.out.println("◇◇◇◇◇ thread1 use time = " +

(endTime - beginTime));

}

}

public static void main(String[] args)

{

for (int i = 0; i < 5; i++)

{

MyThread10_0 mt0 = new MyThread10_0();

mt0.setPriority(5);

mt0.start();

MyThread10_1 mt1 = new MyThread10_1();

mt1.setPriority(4);

mt1.start();

}

}

看下運行結果:

◆◆◆◆◆ thread0 use time = 0

◆◆◆◆◆ thread0 use time = 0

◆◆◆◆◆ thread0 use time = 1

◆◆◆◆◆ thread0 use time = 2

◆◆◆◆◆ thread0 use time = 2

◇◇◇◇◇ thread1 use time = 0

◇◇◇◇◇ thread1 use time = 1

◇◇◇◇◇ thread1 use time = 5

◇◇◇◇◇ thread1 use time = 2

◇◇◇◇◇ thread1 use time = 0

看到黑色菱形(線程優先級高的)先打印完,再多試幾次也是一樣的。為了產生一個對比效果,把yMyThread10_0的優先級設置為4,看下運行結果:

◆◆◆◆◆ thread0 use time = 0

◇◇◇◇◇ thread1 use time = 1

◇◇◇◇◇ thread1 use time = 1

◆◆◆◆◆ thread0 use time = 0

◇◇◇◇◇ thread1 use time = 0

◆◆◆◆◆ thread0 use time = 1

◆◆◆◆◆ thread0 use time = 1

◇◇◇◇◇ thread1 use time = 2

◇◇◇◇◇ thread1 use time = 1

◆◆◆◆◆ thread0 use time = 0

看到,馬上差別就出來了。從這個例子我們得出結論:CPU會盡量將執行資源讓給優先級比較高的線程。

7、isDaeMon、setDaemon(boolean on)

講解兩個方法前,首先要知道理解一個概念。Java中有兩種線程,一種是用戶線程,一種是守護線程。守護線程是一種特殊的線程,它的作用是為其他線程的運行提供便利的服務,最典型的應用便是GC線程。如果進程中不存在非守護線程了,那么守護線程自動銷毀,因為沒有存在的必要,為別人服務,結果服務的對象都沒了,當然就銷毀了。理解了這個概念后,看一下例子:

public class MyThread11 extends Thread

{

private int i = 0;

public void run()

{

try

{

while (true)

{

i++;

System.out.println("i = " + i);

Thread.sleep(1000);

}

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

public static void main(String[] args)

{

try

{

MyThread11 mt = new MyThread11();

mt.setDaemon(true);

mt.start();

Thread.sleep(5000);

System.out.println("我離開thread對象再也不打印了,我停止了!");

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

看一下運行結果:

1 i = 1

2 i = 2

3 i = 3

4 i = 4

5 i = 5

6 我離開thread對象再也不打印了,我停止了!

要解釋一下。我們將MyThread11線程設置為守護線程,看到第6行的那句話,而i停在6不會再運行了。這說明,main線程運行了5秒多結束,而i每隔1秒累加一次,5秒后main線程執行完結束了,MyThread11作為守護線程,main函數都運行完了,自然也沒有存在的必要了,就自動銷毀了,因此也就沒有再往下打印數字。

關于守護線程,有一個細節注意下,setDaemon(true)必須在線程start()之前

8、interrupt()

這是一個有點誤導性的名字,實際上Thread類的interrupt()方法無法中斷線程??匆幌吕?#xff1a;

public class MyThread12 extends Thread

{

public void run()

{

for (int i = 0; i < 500000; i++)

{

System.out.println("i = " + (i + 1));

}

}

}

public static void main(String[] args)

{

try

{

MyThread12 mt = new MyThread12();

mt.start();

Thread.sleep(2000);

mt.interrupt();

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

看下運行結果:

...

i = 499995

i = 499996

i = 499997

i = 499998

i = 499999

i = 500000

看結果還是打印到了50000。也就是說,盡管調用了interrupt()方法,但是線程并沒有停止。interrupt()方法的作用實際上是:在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞狀態。換句話說,沒有被阻塞的線程,調用interrupt()方法是不起作用的。關于這個會在之后講中斷機制的時候,專門寫一篇文章講解。

9、isInterrupted()

測試線程是否已經中斷,但不清除狀態標識。這個和interrupt()方法一樣,在后面講中斷機制的文章中專門會講到。

10、join()

join()方法的作用是等待線程銷毀。join()方法反應的是一個很現實的問題,比如main線程的執行時間是1s,子線程的執行時間是10s,但是主線程依賴子線程執行完的結果,這時怎么辦?可以像生產者/消費者模型一樣,搞一個緩沖區,子線程執行完把數據放在緩沖區中,通知main線程,main線程去拿,這樣就不會浪費main線程的時間了。另外一種方法,就是join()了。先看一下例子:

public class MyThread36 extends Thread

{

public void run()

{

try

{

int secondValue = (int)(Math.random() * 10000);

System.out.println(secondValue);

Thread.sleep(secondValue);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

public static void main(String[] args) throws Exception

{

MyThread36 mt = new MyThread36();

mt.start();

mt.join();

System.out.println("我想當mt對象執行完畢之后我再執行,我做到了");

}

看一下運行結果:

3111

我想當mt對象執行完畢之后我再執行,我做到了

意思是,join()方法會使調用join()方法的線程(也就是mt線程)所在的線程(也就是main線程)無限阻塞,直到調用join()方法的線程銷毀為止,此例中main線程就會無限期阻塞直到mt的run()方法執行完畢。

join()方法的一個重點是要區分出和sleep()方法的區別。join(2000)也是可以的,表示調用join()方法所在的線程最多等待2000ms,兩者的區別在于:

sleep(2000)不釋放鎖,join(2000)釋放鎖,因為join()方法內部使用的是wait(),因此會釋放鎖??匆幌耲oin(2000)的源碼就知道了,join()其實和join(2000)一樣,無非是join(0)而已:

1 public final synchronized void join(long millis)

2 throws InterruptedException {

3 long base = System.currentTimeMillis();

4 long now = 0;

5

6 if (millis < 0) {

7 throw new IllegalArgumentException("timeout value is negative");

8 }

9

10 if (millis == 0) {

11 while (isAlive()) {

12 wait(0);

13 }

14 } else {

15 while (isAlive()) {

16 long delay = millis - now;

17 if (delay <= 0) {

18 break;

19 }

20 wait(delay);

21 now = System.currentTimeMillis() - base;

22 }

23 }

24 }

第12行、第20行應該已經很清楚了。

總結

以上是生活随笔為你收集整理的java中thread实例_Java多线程2:Thread中的实例方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。