標籤:系統管理 run方法 建構函式 color isa 之間 調用順序 繼承 共用資料
一、進程和多線程的概念以及線程的優點
開啟Windo工作管理員可以看到很多正在運行著的exe程式,完全可以將運行在記憶體中的exe檔案理解成進程,進程是受作業系統管理的基本運行單元。
線程可以理解成在進程中獨立啟動並執行子任務。比如,QQ.exe運行時就有很多的子任務在同時運行。
使用線程,可以最大限度地利用CPU的空閑時間來處理其他的任務,CPU在人物之間不停地切換,由於切換速度非常快,所以人們感覺這些任務似乎在同時運行。也就是說看,可以在同一時間內運行更多不同種類的任務,可以大幅增加CPU的利用率。
二、使用多線程
一個進程正在運行時至少會有一個線程在運行。
1 package test;2 3 public class Test {4 5 public static void main(String[] args) {6 System.out.println(Thread.currentThread().getName());7 }8 9 }
輸出為:main。這裡輸出的main其實就是一個名稱叫做main的線程在執行main()方法中的代碼。
1.繼承Thread類
實現多線程編程的方式主要有兩種:一種是繼承Thread類,另一種是實現Runnable介面。從Thread類的結構來看,Thread類實現了Runnable介面,它們之間具有多台關係。為了支援多繼承,完全可以實現Runnable介面的形式,一邊實現一邊繼承。
1.1線程的調用的隨機性
1 public class MyThread extends Thread {2 @Override3 public void run() {4 super.run();5 System.out.println("MyThread");6 }7 }
1 package test; 2 3 import com.mythread.www.MyThread; 4 5 public class Run { 6 7 public static void main(String[] args) { 8 MyThread mythread = new MyThread(); 9 mythread.start();10 System.out.println("運行結束");11 }12 13 }
運行結束MyThread
從輸出結果可以看出,代碼的運行結果與代碼執行順序或調用順序是無關的,線程是一個子任務,CPU以不確定的方式,或者說是以隨機的時間來調用線程中的run方法。
1.2 示範線程的隨機性
1 package mythread; 2 3 public class MyThread extends Thread { 4 @Override 5 public void run() { 6 try { 7 for (int i = 0; i < 10; i++) { 8 int time = (int) (Math.random() * 1000); 9 Thread.sleep(time);10 System.out.println("run=" + Thread.currentThread().getName());11 }12 } catch (InterruptedException e) {13 e.printStackTrace();14 }15 }16 }
1 package test; 2 3 import mythread.MyThread; 4 5 public class Test { 6 public static void main(String[] args) { 7 try { 8 9 MyThread thread = new MyThread();10 thread.setName("myThread");11 thread.start();12 13 for (int i = 0; i < 10; i++) {14 int time = (int) (Math.random() * 1000);15 Thread.sleep(time);16 System.out.println("main=" + Thread.currentThread().getName());17 }18 } catch (InterruptedException e) {19 e.printStackTrace();20 }21 }22 }
main=mainmain=mainrun=myThreadmain=mainrun=myThreadrun=myThreadmain=mainmain=mainrun=myThreadmain=mainmain=mainrun=myThreadmain=mainmain=mainrun=myThreadrun=myThreadrun=myThreadmain=mainrun=myThreadrun=myThread
從輸出的20個結果可以看出,Thread.java類中的start()方法通知“線程規劃器”此線程已經準備就緒,等待調用線程對象的run()方法。這個過程其實就是讓系統安排一個時間來調用Thread中的run()方法,也就是使線程得到運行,啟動線程,具有非同步執行的效果。
1.3 同步執行
如果調用thread.run()方法就不是非同步執行了,而是同步,那麼此線程對象並不交給“線程規劃器”來進行處理,而是由main主線程來調用run()方法,也就是必須等run()方法中的代碼執行完後才可以執行後面的代碼。
1 package extthread; 2 3 public class MyThread extends Thread { 4 5 private int i; 6 7 public MyThread(int i) { 8 super(); 9 this.i = i;10 }11 12 @Override13 public void run() {14 System.out.println(i);15 }16 17 }
1 package test; 2 3 import extthread.MyThread; 4 5 public class Test { 6 7 public static void main(String[] args) { 8 MyThread t11 = new MyThread(1); 9 MyThread t12 = new MyThread(2);10 MyThread t13 = new MyThread(3);11 MyThread t14 = new MyThread(4);12 MyThread t15 = new MyThread(5);13 MyThread t16 = new MyThread(6);14 MyThread t17 = new MyThread(7);15 MyThread t18 = new MyThread(8);16 MyThread t19 = new MyThread(9);17 MyThread t110 = new MyThread(10);18 MyThread t111 = new MyThread(11);19 MyThread t112 = new MyThread(12);20 MyThread t113 = new MyThread(13);21 22 t11.start();23 t12.start();24 t13.start();25 t14.start();26 t15.start();27 t16.start();28 t17.start();29 t18.start();30 t19.start();31 t110.start();32 t111.start();33 t112.start();34 t113.start();35 36 }37 38 }
23145768109111213
從輸出結果可以看出,start()方法的順序並不代表線程啟動的順序。
2.實現Runnable介面
如果想要建立的線程類已經有一個父類了,這時就不能再繼承自Thread類了,因為Java不支援多繼承,所以就需要實現Runnable介面。
1 package myrunnable;2 3 public class MyRunnable implements Runnable {4 @Override5 public void run() {6 System.out.println("myrunnable類中的run!");7 }8 }
1 package test; 2 3 import myrunnable.MyRunnable; 4 5 public class Run { 6 7 public static void main(String[] args) { 8 Runnable runnable=new MyRunnable(); 9 Thread thread=new Thread(runnable);10 thread.start();11 System.out.println("run中的main!");12 }13 14 }
run中的main!myrunnable類中的run!
Thread.java類的8個建構函式中,有兩個可以傳遞Runnable介面的對象,並且由於Thread類也實現了Runnable介面,所以也就意味著建構函式Thread(Runnable target)不光可以傳入Runnable介面的對象, 還可以傳入一個Thread類的對象,這樣做完全可以將一個Thread對象中的run()方法交由其他的線程進行調用。
3.執行個體變數與安全執行緒
自訂線程類中的執行個體變數針對其他線程可以有共用與不共用之分。
3.1 不共用資料
3.2 共用資料
4.留意i--與System.out.println()的異常
三、currentThread()方法
四、isAlive()方法
五、sleep()方法
六、getId()方法
七、停止線程
1.停止不了的線程
2.判斷線程是否是停止狀態
3.能停止的線程--異常法
4.在沉睡中停止
5.能停止的線程--暴力停止
6.方法stop()與java.lang.ThreadDeath異常
7.釋放鎖的不良後果
8.使用return停止線程
八、暫停線程
1.suspend與resume方法的使用
2.suspend與resume方法的缺點--獨佔
3.suspend與resume方法的缺點--不同步
九、yield()方法
十、線程的優先順序
1.線程優先順序的繼承特性
2.優先順序具有規則性
3.優先順序具有隨機性
4.看誰運行得快
十一、守護線程
Java多線程編程(一)Java多線程技能