java並發-線程
前言
近來時間比較充裕,正好又看了一遍《實戰java高並發程序設計》,故而對java並發一些知識進行下總結,算是溫故而知新吧。
一,線程基礎
1,新建線程
一般有兩種實現方式實現Runnable接口或繼承Thread類(Thread類本身也是實現Runnable接口)
public class Test { public static void main(String[] args) throws Exception { Thread t1=new TestThread(); Thread t2=new TestThread(); Thread t3=new Thread(new TestThreadImpl()); Thread t4=new Thread(new TestThreadImpl()); t1.start(); t2.start(); t3.start(); t4.start(); } } class TestThread extends Thread{ @Override public void run() { System.out.println("hello word"); } }class TestThreadImpl implements Runnable{ @Override public void run() { System.out.println("hello word 2"); } }
2,線程的終止
一般來說線程在執行完畢後就會結束無須手動關閉,但凡是總有例外一下服務端的後臺線程可能會常駐系統,比如它們本身就是一個無限循環,用於提供默寫服務。
Thread 提供了一個被標註為廢棄的方法stop();因為stop()方法過於暴力,強行把執行一般的線程終止,這樣可能會引起一些數據不一致的問題。《實戰java高並發程序設計》中給出了一個的解決方案,用一個一個自定義的stop並且需要自行決定何時退出
class ChangeObjectThread extends Thread{ volatile boolean stopme=false; public void stopMe(){ stopme=true; } @Override public void run() { while(true){ if(stopme){ break; } //synchromized handle data } } }
3,線程中斷interrupt
嚴格來講,線程中斷並不會讓線程立即退出,而是給線程發送一個通知,告知目標線程 ,有人希望你退出了。至於目標線程街道通知後如何處理,則完全有線程自行決定,如果無條件退出那麽又遇到和stop()相同的問題了。
public void interrupt() //中斷線程 public boolean isInterrupted()//判斷是否被中斷 public static boolean interrupted()//判斷是否被中斷,並清除當前中斷狀態
public class Test { public static Object o = new Object(); public static void main(String[] args) throws Exception { Thread t1 = new TestThread(); t1.start(); Thread.sleep(1000); t1.interrupt(); } } class TestThread extends Thread { @Override public void run() { int i=0; while (!isInterrupted()) { i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } }
另:當線程由於被調用了sleep(), wait(), join()等方法而進入阻塞狀態;若此時調用線程的interrupt()將線程的中斷標記設為true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException異常,這時就要用合適的方式處理InterruptedException了
4,Object 等待(wait)和通知(notify)
這兩個方法是由Object類提供的,並不是在Thread中的。當一個對象實例調用了wait()方法後,當前線程就會在這個對象上等待。如:線程A中調用了obj.wait()方法,那麽線程A就會停止繼續執行,而轉為等待狀態,直到調用了obj.notify()方法為止。
wait(),notify()方法的調用鼻血包含在對應的synchronized語句中,也就是要先獲得目標對象鎖資源。調用了wait後,會釋放鎖資源。
public class Test { public static Object o = new Object(); public static void main(String[] args) throws Exception { Thread t1 = new TestThread(); Thread t2 = new TestThread(); Thread t3 = new TestThread(); Thread t4 = new TestThreadNotify(); t1.start(); t2.start(); t3.start(); t4.start(); } } class TestThread extends Thread { @Override public void run() { synchronized (Test.o) { try { System.out.println(Thread.currentThread().getName()+"waiting...."); Test.o.wait(); System.out.println(Thread.currentThread().getName()+"start...."); Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"stop...."); } } } class TestThreadNotify extends Thread { @Override public void run() { synchronized (Test.o) { System.out.println("TestThreadNotify start...."); try { Test.o.notifyAll(); } catch (Exception e) { e.printStackTrace(); } System.out.println("TestThreadNotify stop...."); } } } }
Thread-0waiting.... TestThreadNotify start.... TestThreadNotify stop.... Thread-2waiting.... Thread-1waiting.... Thread-0start.... Thread-0stop....
5,等待線程結束(join)和謙讓(yield)
很多時候,一個線程的輸入可能非常依賴於另外一個或者多個線程的輸出,此時,這個線程就需要等待依賴線程執行完畢,才能繼續執行。JDK 提供了join()操作來實現這個功能,如下所示,顯示了2個join()方法:
public final void join() throws InterruptedException public final synchronized void join(long millis) throws InterruptedException
第一個join()方法表示無限等待,它會一直阻塞當前線程,直到目標線程執行完畢。
第二個方法給出了一個最大等待時間,如果超過給定時間目標線程還在執行,當前線程也會因為“等不及了”,而繼續往下執行。
join()的本質是讓調用線程wait()在當前線程對象實例上;
public class Test { public volatile static int i = 0; public static class AddThread extends Thread { @Override public void run() { for (i = 0; i < 10000000; i++); } } public static void main(String[] args) throws InterruptedException { AddThread at = new AddThread(); at.start(); at.join(); System.out.println(i); } }
主函數中,如果不使用join()等待AddThread ,那麽得到的i 很可能是0或者一個非常小的數字。因為AddThread 還沒開始執行,i 的值就已經被輸出了。但在使用join()方法後,表示主線程願意等待AddThread 執行完畢,跟著AddThread 一起往前走,故在join()返回時,AddThread 已經執行完成,故i 總是10000000
yiead()
這是一個靜態方法,一旦執行,它會使當前線程讓出CPU 。但要註意,讓出CPU 並不表示當前線程不執行了。當前線程在讓出CPU 後,還會進行CPU 資源的爭奪,但是是否能夠再次被分配到,就不一定了
待續
java並發-線程