Java線程--基本知識
大部分時候,我們做的是單線程編程,但實際情況是,單線程的程序往往功能有限,這就需要使用多線程。Java中程序運行時就啓動了兩個線程:
1.Main線程:調用main方法,執行main方法。
2.GC線程:在main線程運行時運行,回收程序運行之中的垃圾。
線程就是一條執行路徑。多線程完成多個功能併發併發執行的效果。
那麼如何來寫多線程呢?寫多線程有兩種方式:
1. 繼承自Thread類,重寫run方法。然後用Thread的start方法啓動線程。
2. 實現Runnable接口,實現run方法。然後用Thread的start方法啓動線程。
這兩種方式的區別是:
1. 第一種使用簡單。
2. 第二種不受java單繼承的限制。一般來說,都是用第二種。
多線程執行順序是:多線程之間亂序執行、同一線程內部順序執行。
線程中常用的方法:
線程中的已過時方法禁止使用。其他類中的過時方法不建議使用。
1. start:啓動一個新線程。啓動之後jvm會自動執行run方法。
2. run:線程啓動之後執行的方法。
3. setName、getName:自動命名,Thread-0,1…
4. currentThread:得到當前運行的線程。
5. getPriority()、setPriority 得到和設置當前線程的優先級。優先級1-10,如果不指定默認是5. 理論上,誰優先級高,誰被cpu調度的可能性就大。但是優先級低的並不是不執行。資源不足的時候纔有效果。
6. setDaemon:將線程置爲守護線程。只能在線程start之前調用。一般用於爲其他線程提供服務,比如GC。守護線程會隨着其他非守護線程的結束而結束。isDaemon可以用於判斷某個線程是否是守護線程。
7. sleep:讓當前線程停止執行(休眠)一段時間。
8. join:如果在A線程中B線程join進來,則現在執行B的內容,直到B執行完畢才繼續執行A。比如A是顯示數據 B是收集收據。
9. yield:讓位:讓出執行權,和其他線程爭奪資源,誰拿到cpu時間片誰執行。
下面讓我們通過具體例子來分別理解一下多線程中的各個方法:
先看一下寫多線程的第一種方式:
public class TestThread { public static void main(String[] args) { MyThread mt = new MyThread(); mt.start();//啓動線程 // mt.run();// 屬於方法的調用,沒有開新線程。整個就一個main線程。 for(int i = 0;i<100;i++){ System.out.println("main-->"+i); } } } class MyThread extends Thread{ @Override public void run() { for(int i = 0;i<100;i++){ System.out.println("run-->"+i); } } } 由於執行結果在每臺電腦上是不一樣的,所以大家可以自己驗證一下。
再看一下第二種方式:
public class TestRunable { public static void main(String[] args) { MyRun mr = new MyRun(); Thread th = new Thread(mr/*,"新線程"*/); // th.setName("新線程");//設置名字 // Thread.currentThread().setName("主線程"); // Thread.currentThread()獲得當前正在運行的線程 th.start();//啓動新線程 // Thread th1 = new Thread(mr/*,"新線程"*/); // th1.start(); for(int i = 0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class MyRun implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ //如果不給線程起名字,默認的是Thread-0如果在多一個線程,則爲Thread-1,以此類推 System.out.println(Thread.currentThread().getName()+"-->"+i); } } } 這裏設置名字在實際中是不需要的,我們通常使用默認的,即用Thread.currentThread()這個方法
接下來說一下優先級的問題:
public class TestProirity { public static void main(String[] args) { Run r = new Run(); Thread th1 = new Thread(r); th1.setPriority(10);//優先級最高是10 th1.start(); Thread th2 = new Thread(r); th2.setPriority(1);//優先級最低是1 th2.start(); // System.out.println(th1.getPriority());//默認線程的優先級是5 } } class Run implements Runnable{ @Override public void run() { for(int i = 0;i<10000;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } 如果執行次數很少的話,優先級的作用不是很明顯,所以這裏執行次數多一些。
接下來是守護線程:
public class TestDaemon { public static void main(String[] args) { Run1 r = new Run1(); Thread th1 = new Thread(r); th1.setDaemon(true);//設置爲守護線程 th1.isDaemon();//判斷是否是守護線程 th1.start(); for(int i = 0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Run1 implements Runnable{ @Override public void run() { while(true){ System.out.println("我是守護線程"); } } } 如果不設置爲守護線程,那麼線程會一直執行下去,而設置爲守護線程之後,守護線程就會隨着其他線程的結束。
接下來是睡眠:
public class TestSleep { public static void main(String[] args) { Run2 r = new Run2(); Thread th = new Thread(r); th.start(); for(int i = 0;i<100;i++){ try { th.sleep(1000);//睡眠一秒鐘 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Run2 implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+i); } } } 加入sleep()之後我們會發現執行結果是每一秒顯示一句。
接下來是join
public class TestJoin { public static void main(String[] args) { MyRun1 mr = new MyRun1(); Thread th = new Thread(mr); th.start();//啓動新線程 try { th.join();// 在main中把th1加進來,th1就先執行,執行完畢後main才能繼續執行 } catch (InterruptedException e) { e.printStackTrace(); } for(int i = 0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class MyRun1 implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } 執行結果是先執行完thread中的然後再執行main中的。
接下來是yield:
public class TestYield { public static void main(String[] args) { MyRun2 mr = new MyRun2(); Thread th = new Thread(mr); th.start(); for(int i = 0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class MyRun2 implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ System.out.println("讓你執行"); Thread.yield();//讓位 System.out.println(Thread.currentThread().getName()+"-->"+i); } } } 執行結果大家可以自己驗證一下,有一點需要注意就是yield只是讓出執行權而並不是不執行了。
線程的東西就先說這麼多吧!剩下的再補充。