Java中的多線程有三種實現方式:
1.繼承Thread類,重寫run方法。Thread本質上也是一個實現了Runnable的實例,他代表一個線程的實例,并且啟動線程的唯一方法就是通過Thread類的start方法。
2.實現Runnable接口,并實現該接口的run()方法.創建一個Thread對象,用實現的Runnable接口的對象作為參數實例化Thread對象,調用此對象的start方法。
3.實現Callable接口,重寫call方法。Callable接口與Runnable接口的功能類似,但提供了比Runnable更強大的功能。有以下三點
1).Callable可以在人物結束后提供一個返回值,Runnable沒有提供這個功能。
2).Callable中的call方法可以拋出異常,而Runnable的run方法不能拋出異常。
3).運行Callable可以拿到一個Future對象,表示異步計算的結果,提供了檢查計算是否完成的方法。
需要注意的是,無論用那種方式實現了多線程,調用start方法并不意味著立即執行多線程代碼,而是使得線程變為可運行狀態。
run start的區別
start方法是啟動一個線程,而線程中的run方法來完成實際的操作。
如果開發人員直接調用run方法,那么就會將這個方法當作一個普通函數來調用,并沒有多開辟線程,開發人員如果希望多線程異步執行,則需要調用start方法。
sleep wait的區別
1.兩者處理的機制不同,sleep方法主要是,讓線程暫停執行一段時間,時間一到自動恢復,并不會釋放所占用的鎖,當調用wait方法以后,他會釋放所占用的對象鎖,等待其他線程調用notify方法才會再次醒來。
2.sleep是Threa的靜態方法,是用來控制線程自身流程的,而wait是object的方法,用于進行線程通信。
3.兩者使用的區域不同。sleep可以在任何地方使用,wait必須放在同步控制方法,或者語句塊中執行。
synchronized notify wait的運用
synchronized關鍵字有兩種用法,synchronized方法和synchronized語句塊。
public synchronized void function(){}
synchronized(object){}
當某個資源被synchronized所修飾,線程1線程2等多個線程在共同請求這個資源,線程1先請求到,調用了對象的wait方法釋放了對象的鎖,此時線程2可以對這個對象進行訪問,在工作結束時可以調用對象的notify方法,喚醒等待隊列中正在等待的線程,此時被喚醒的線程將會再一次拿到對象鎖,對對象進行操作??梢哉{用notifyAll方法,喚醒等待隊列中的所有線程。
需要注意的是一個線程被喚醒不代表立即獲取對象鎖,必須等調用的線程對象的方法推出synchronized塊釋放對象鎖后,被喚醒的進程才會獲得對象鎖。
以下為大家提供一個簡單的代碼實例:
分別用Runnable和Thread方法實現,展示各個方法的
實現Runnable實現多線程的方法
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
|
public class TestRunnable implements Runnable { private int time= 1 ; private SourceA s; private String id = "001" ; public TestRunnable(SourceA s){ this .s = s; } public void setTime( int time) { this .time = time; } @Override public void run() { try { System.out.println( "i will sleep" + time); Thread.sleep(time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (s){ s.notify(); System.out.println( "我喚醒了002!" ); System.out.println( "我存入了id" +id); s.setSource(id); } } } |
繼承Thread實現多線程的方法
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
|
public class TestThread extends Thread { private int time = 1 ; private SourceA s = null ; String id = "002" ; public void setTime( int time) { this .time = time; } public TestThread(SourceA s){ this .s = s ; } @Override public void run() { try { System.out.println( "i will sleep" + time); sleep(time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (s){ try { System.out.println( "我" + id + "要進行等待了" ); s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println( "我被喚醒了" ); System.out.println( "我存入了id" +id); s.setSource(id); } } } |
SourceA類代碼:
1
2
3
4
5
6
7
8
9
10
11
|
public class SourceA { private List<String> list = new ArrayList<String>(); public synchronized void getSource(){ for ( int i= 0 ;i<list.size();i++){ System.out.println(list.get(i)); } } public synchronized void setSource(String id){ list.add(id); } } |
Test測試類代碼:
1
2
3
4
5
6
7
8
9
10
|
public void test(){ SourceA s = new SourceA(); TestThread tt = new TestThread(s); TestRunnable tr = new TestRunnable(s); Thread t = new Thread(tr); System.out.println( "調用線程1" ); tt.start(); System.out.println( "調用線程2" ); t.start(); } |
結果圖片: