先看一下java線(xiàn)程運(yùn)行時(shí)各個(gè)階段的運(yùn)行狀態(tài)
線(xiàn)程是進(jìn)程中的一個(gè)實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位,線(xiàn)程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源,但它可與同屬一個(gè)進(jìn)程的其它線(xiàn)程共享進(jìn)程所擁有的全部資源。一個(gè)線(xiàn)程可以創(chuàng)建和撤消另一個(gè)線(xiàn)程,同一進(jìn)程中的多個(gè)線(xiàn)程之間可以并發(fā)執(zhí)行。由于線(xiàn)程之間的相互制約,致使線(xiàn)程在運(yùn)行中呈現(xiàn)出間斷性。
在引入線(xiàn)程的操作系統(tǒng)中,通常都是把進(jìn)程作為分配資源的基本單位,而把線(xiàn)程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位。由于線(xiàn)程比進(jìn)程更小,基本上不擁有系統(tǒng)資源,故對(duì)它的調(diào)度所付出的開(kāi)銷(xiāo)就會(huì)小得多,能更高效的提高系統(tǒng)內(nèi)多個(gè)程序間并發(fā)執(zhí)行的程度,從而顯著提高系統(tǒng)資源的利用率和吞吐量。
線(xiàn)程是程序中一個(gè)單一的順序控制流程。在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線(xiàn)程完成不同的工作,稱(chēng)為多線(xiàn)程。
多線(xiàn)程主要是為了節(jié)約CPU時(shí)間,發(fā)揮利用,線(xiàn)程的運(yùn)行中需要使用計(jì)算機(jī)的內(nèi)存資源和CPU。
多線(xiàn)程是為了同步完成多項(xiàng)任務(wù),不是為了提高運(yùn)行效率,而是為了提高資源使用效率來(lái)提高系統(tǒng)的效率。線(xiàn)程是在同一時(shí)間需要完成多項(xiàng)任務(wù)的時(shí)候?qū)崿F(xiàn)的。
java實(shí)現(xiàn)多線(xiàn)程有兩種方法
1、繼承Thread類(lèi)
2、實(shí)現(xiàn)Runnable接口
這兩種方法的共同點(diǎn):
不論用哪種方法,都必須用Thread(如果是Thead子類(lèi)就用它本身)產(chǎn)生線(xiàn)程,然后再調(diào)用start()方法。
兩種方法的不同點(diǎn):
1、繼承Thread類(lèi)有一個(gè)缺點(diǎn)就是單繼承,而實(shí)現(xiàn)Runnable接口則彌補(bǔ)了它的缺點(diǎn),可以實(shí)現(xiàn)多繼承
2、繼承Thread類(lèi)必須如果產(chǎn)生Runnable實(shí)例對(duì)象,就必須產(chǎn)生多個(gè)Runnable實(shí)例對(duì)象,然后再用Thread產(chǎn)生多個(gè)線(xiàn)程;而實(shí)現(xiàn)Runnable接口,只需要建立一個(gè)實(shí)現(xiàn)這個(gè)類(lèi)的實(shí)例,然后用這一個(gè)實(shí)例對(duì)象產(chǎn)生多個(gè)線(xiàn)程。即實(shí)現(xiàn)了資源的共享性
基于以上兩點(diǎn)所以建議用第二種方法
下面用例子來(lái)做說(shuō)明
程序1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.dr.runnable1; //一個(gè)類(lèi)只要繼承了Thread類(lèi),則此類(lèi)就是多線(xiàn)程類(lèi) class MyThread extends Thread { private String name; public MyThread(String name) { this .name=name; } //如果要使用多線(xiàn)程,則必須有一個(gè)方法的主體 public void run() { //打印輸出 for ( int i= 0 ;i< 10 ;i++) { System.out.println( this .name+ "----->運(yùn)行、、、、" ); } } } public class Demo1 { public static void main(String args[]) { //第一種方法 Runnable r1= new MyThread( "線(xiàn)程A" ); Runnable r2= new MyThread( "線(xiàn)程B" ); Runnable r3= new MyThread( "線(xiàn)程C" ); Thread t1= new Thread(r1); Thread t2= new Thread(r2); Thread t3= new Thread(r3); t1.start(); t2.start(); t3.start(); // mt1.run();//線(xiàn)程執(zhí)行,使用start方法 // mt2.run(); // mt3.run(); //第二種方法 // MyThread mt1=new MyThread("線(xiàn)程A"); // MyThread mt2=new MyThread("線(xiàn)程B"); // MyThread mt3=new MyThread("線(xiàn)程C"); // mt1.start(); // mt1.start();//線(xiàn)程只能啟動(dòng)一次 // mt2.start(); // mt3.start(); } } |
程序的運(yùn)行結(jié)果是:
這是繼承了Thread類(lèi),第一種方法產(chǎn)生多個(gè)Runnable實(shí)例對(duì)象,然后用Thread產(chǎn)生多個(gè)線(xiàn)程
第二種方法,因?yàn)檫@個(gè)類(lèi)已經(jīng)繼承了Thread類(lèi),所以就可以直接利用它本身產(chǎn)生多個(gè)線(xiàn)程
程序2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.dr.runnable1; class MyThread1 implements Runnable { private int ticket=10; public void run() { for (int i=0;i<500;i++) { if (this.ticket>0) { System.out.println( "賣(mài)票----->" +(this.ticket--)); } } } } public class Demo2 { public static void main(String args[]) { MyThread1 mt= new MyThread1(); Thread t1= new Thread(mt); Thread t2= new Thread(mt); Thread t3= new Thread(mt); t1.start(); t2.start(); t3.start(); } } |
程序運(yùn)行結(jié)果:
這個(gè)程序是實(shí)現(xiàn)Runnable了,產(chǎn)生一類(lèi)的實(shí)例對(duì)象,然后用Thread產(chǎn)生多個(gè)線(xiàn)程。