以前學習基礎的時候學習了一段時間的多線程,上課的時候老師也講過一遍,那時候感覺學的似懂非懂。因為到現在很長一段時間沒有用到多線程的知識,所以現在基本上忘了差不多了。但是下個星期要面試了,所以今天特意又研究了一下多線程,免得被問到多線程問題時什么都不記得了那就麻煩了?,F在對java比較熟悉了,所以再一次學習多線程知識,感覺沒有那么難了(記得剛接觸多線程的時候,感覺非常吃力)。
首先講一下進程和線程的區別:
進程:每個進程都有獨立的代碼和數據空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1--n個線程。
線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。
線程和進程一樣分為五個階段:創建、就緒、運行、阻塞、終止。
多進程是指操作系統能同時運行多個任務(程序)。
多線程是指在同一程序中有多個順序流在執行。
在java中創建一個線程有兩種方法:
?、賹崿Fjava.lang.Runnable接口,重寫run()方法,啟動:new Thread(this).start()。
1 package com.thread; 2 3 public class ThreadTest1 { 4 public static void main(String[] args) { 5 Runnable1 r = new Runnable1(); 6 //r.run();并不是線程開啟,而是簡單的方法調用 7 Thread t = new Thread(r);//創建線程 8 //t.run(); //如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作并返回。 9 t.start(); //線程開啟10 for (int i = 0; i < 100; i++) {11 System.out.i);12 }13 }14 }15 class Runnable1 implements Runnable{16 public void run() {17 for (int i = 0; i < 100; i++) {18 System.out.println("Thread-----:"+i);19 }20 }21 }
要注意的是:
1.r.run()并不是啟動線程,而是簡單的方法調用。
2.Thread也有run()方法,如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作并返回。
3.并不是一啟動線程(調用start()方法)就執行這個線程,而是進入就緒狀態,什么時候運行要看CUP。
?、诶^承java.lang.Thread類,重寫run()方法。
1 package com.thread; 2 3 public class TestThread2 { 4 public static void main(String[] args) { 5 Thread1 t = new Thread1(); 6 //t.run(); //這里也不能直接調用方法 7 t.start(); 8 for (int i = 0; i < 100; i++) { 9 System.out.println("main:"+i);10 }11 }12 }13 14 //盡量使用實現Runnnable接口,因為接口比較靈活15 class Thread1 extends Thread{16 @Override17 public void run() {18 for (int i = 0; i < 100; i++) {19 System.out.println("Thread-----:"+i);20 }21 }22 }
雖然兩種方法都可行,但是最好還是用第一種方法,因為使用接口靈活性好,java中時單繼承、多實現。
Thread類中常用的方法有:
①sleep(long millis): 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)。
1 package com.thread; 2 import java.util.Date; 3 /** 4 * sleep()指在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)。 5 * @author Administrator 6 * 7 */ 8 public class SleepTest { 9 public static void main(String[] args) {10 Thread2 t = new Thread2();11 t.start();12 try {13 Thread.sleep(10000); //主線程睡眠10秒鐘14 } catch (InterruptedException e) {15 e.printStackTrace();16 }17 //主線程睡眠10秒鐘后結束t線程18 //t.interrupt(); //這種結束方式比較粗暴,如果t線程打開了某個資源還沒來得及關閉也就是run方法還沒有執行完就強制結束線程,會導致資源無法關閉19 //t.stop();也是結束某個線程,這種方式比interrupt()更粗暴20 t.flag = false;21 }22 }23 class Thread2 extends Thread{24 boolean flag = true; //用這種方式結束線程很不錯,用一個變量控制run方法什么時候不再執行,不會出現run方法沒有執行完畢就結束25 @Override26 public void run() { //run方法一結束,整個線程就終止了27 while(flag){28 System.out.println("---"+new Date()+"---");29 try {30 sleep(1000);31 } catch (InterruptedException e) {32 return;33 }34 }35 }36 }
②join():指等待t線程終止。也可以理解為將t線程合并到當前線程來,等待t線程結束后再往下執行。相當于方法調用
1 package com.thread; 2 3 import java.util.Date; 4 5 /* 6 * t.join()方法指等待t線程終止。也可以理解為將t線程合并到當前線程來,等待t線程結束后再往下執行。相當于方法調用 7 */ 8 public class TestJoin { 9 public static void main(String[] args) {10 Thread t = new Thread3("abc");11 t.start();12 for (int i = 0; i < 20; i++) {13 System.out.println("我是main線程");14 if(i==10){15 try {16 t.join();17 } catch (InterruptedException e1) {18 // TODO Auto-generated catch block19 e1.printStackTrace();20 }21 }22 try {23 Thread.sleep(1000);24 } catch (InterruptedException e) {25 e.printStackTrace();26 }27 }28 }29 }30 class Thread3 extends Thread{31 public Thread3(String s) { //給該線程取一個名字,用getName()方法可以去到該名字32 super(s);33 }34 @Override35 public void run() {36 for (int i = 0; i < 20; i++) {37 System.out.println("我是"+getName()+"線程");38 try {39 sleep(1000);40 } catch (InterruptedException e) {41 e.printStackTrace();42 }43 }44 }45 }
運行該程序結果為:
1 我是main線程 2 我是abc線程 3 我是main線程 4 我是abc線程 5 我是main線程 6 我是abc線程 7 我是main線程 8 我是abc線程 9 我是main線程10 我是abc線程11 我是main線程12 我是abc線程13 我是main線程14 我是abc線程15 我是main線程16 我是abc線程17 我是main線程18 我是abc線程19 我是main線程20 我是abc線程21 我是main線程22 我是abc線程23 我是abc線程24 我是abc線程25 我是abc線程26 我是abc線程27 我是abc線程28 我是abc線程29 我是abc線程30 我是abc線程31 我是abc線程32 我是main線程33 我是main線程34 我是main線程35 我是main線程36 我是main線程37 我是main線程38 我是main線程39 我是main線程40 我是main線程
可以看到從第22行起就開始順序執行了,因為i=10的時候就將該形成合并了。
?、踶ield():暫停當前正在執行的線程對象,并執行其他線程。
?、躶etPriority(): 更改線程的優先級。
MIN_PRIORITY = 1
NORM_PRIORITY = 5
MAX_PRIORITY = 10
1 package com.thread; 2 3 4 /*t.yield()暫停當前正在執行的線程對象,并執行其他線程。 5 * 6 * MIN_PRIORITY 1 7 * NORM_PRIORITY 5 8 * MAX_PRIORITY 10 9 */10 public class TestYield {11 public static void main(String[] args) {12 Thread4 t1 = new Thread4("t1");13 Thread4 t2 = new Thread4("t2");14 t1.setPriority(Thread.MAX_PRIORITY);15 t2.setPriority(Thread.MIN_PRIORITY);16 System.out.println(t1.getPriority());17 System.out.println(t2.getPriority());18 t1.start();19 t2.start();20 21 }22 }23 class Thread4 extends Thread{24 public Thread4(String s) { 25 super(s);26 }27 @Override28 public void run() {29 for (int i = 0; i < 1000; i++) {30 System.out.println("我是"+getName()+"線程"+i);31 if(i%10 == 0){32 yield();33 }34 }35 }36 }
由于運行結果太長就沒有貼上來了,運行該程序,可以看到t1和t2兩個進程每次當i為10的倍數時都會讓給其他線程執行。
?、輎nterrupt():中斷某個線程,這種結束方式比較粗暴,如果t線程打開了某個資源還沒來得及關閉也就是run方法還沒有執行完就強制結束線程,會導致資源無法關閉
要想結束進程最好的辦法就是用sleep()函數的例子程序里那樣,在線程類里面用以個boolean型變量來控制run()方法什么時候結束,run()方法一結束,該線程也就結束了。
?、捱€有很多的方法就不一一列舉了.........
當然,多線程難點不在這些,多線程的難點在于多線程之間的協調。關于多線程的協調待續....
新聞熱點
疑難解答