生活随笔
收集整理的這篇文章主要介紹了
线程的三种创建方式以及代码实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
線程和進程的概念
一個進程可以有多個線程
程序:是指令和數據的有序集合(靜態的)
進程:是執行程序的一次執行過程(動態的),是系統資源分配的單位。在操作系統中運行的程序就是進程。
通常在一個進程中可以包含若干個線程,當然一個進程中至少有一個線程,是主線程。
線程是CPU調度和執行的單位。
注意:很多多線程是模擬出來的,真正的多線程是指有多個CPU,即多核,如服務器。如果是模擬出來的多線程,在一個cpu的情況下,在同一個時間點,cpu只能執行一個代碼,因為切換的很快,所以就造成同時執行的錯覺。
核心概念
線程就是獨立的執行路徑; 在程序運行時,即使沒有自己創建線程,后臺也會有多個線程,如主線程,gc線程;main()稱之為主線程,為系統的入口,用于執行整個程序; 在一個進程中,如果開辟了多個線程,線程的運行由調度器安排調度,調度器是與操作系統緊密相關的,先后順序是不能認為的干預的。 對同一份資源操作時,會存在資源搶奪的問題,需要加入并發控制;線程會帶來額外的開銷,如cpu調度時間,并發控制開銷。 每個線程在自己的工作內存交互,內存控制不當會造成數據不一致。
線程的創建
三種創建方式:
繼承Thread類 實現Runnable接口 實現Callable接口(前兩個是重點,這個了解即可)
方法一:繼承Thread類
自定義線程類繼承Thread類 重寫run()方法,編寫線程執行體 創建線程對象,調用start()方法啟動線程
public class ThreadDemo extends Thread { @Override public void run ( ) { for ( int i
= 0 ; i
< 20 ; i
++ ) { System
. out
. print ( "run" + i
+ " " ) ; } } public static void main ( String
[ ] args
) { ThreadDemo threadDemo
= new ThreadDemo ( ) ; threadDemo
. run ( ) ; System
. out
. print ( "\n" ) ; for ( int i
= 0 ; i
< 20 ; i
++ ) { System
. out
. print ( "main" + i
+ " " ) ; } }
}
普通方法調用和多線程:
調用run()方法開啟線程,實際上只有主線程一條執行路徑,按照主線程中代碼的順序依次執行。 調用start()方法開啟線程,有多條執行路徑,主線程和子線程并行交替執行。 而且每次結果不一樣 注意:線程開啟不一定立即執行,由CPU調度執行 小栗子:
package com
. yxy
; import org
. apache
. commons
. io
. FileUtils
; import java
. io
. File
;
import java
. io
. IOException
;
import java
. net
. MalformedURLException
;
import java
. net
. URL
; public class ThreadDemo2 extends Thread { private String url
; private String name
; public ThreadDemo2 ( String url
, String name
) { this . url
= url
; this . name
= name
; } @Override public void run ( ) { WebDownLoader webDownLoader
= new WebDownLoader ( ) ; webDownLoader
. downloader ( url
, name
) ; System
. out
. println ( "下載的文件名為:" + name
) ; } public static void main ( String
[ ] args
) { ThreadDemo2 threadDemo1
= new ThreadDemo2 ( "http://new-img3.ol-img.com/moudlepic/199_module_images/201707/5976d99c3d918_822.jpg" , "1.jpg" ) ; ThreadDemo2 threadDemo2
= new ThreadDemo2 ( "http://hzp.onlylady.com/qitamianbumeihu_index/filorga/pic_436152_1_1.html?imgUrl=http://p1.ol-cdn.com/product/100x100/5/437/5c6fa83739d64.jpg" , "2.jpg" ) ; ThreadDemo2 threadDemo3
= new ThreadDemo2 ( "http://hzp.onlylady.com/mianshuang_index/filorga/pic_436150_1_1.html?imgUrl=http://p1.ol-cdn.com/product/100x100/5/437/5c6fa724101a3.jpg" , "3.jpg" ) ; threadDemo1
. start ( ) ; threadDemo2
. start ( ) ; threadDemo3
. start ( ) ; }
} class WebDownLoader { public void downloader ( String url
, String name
) { try { FileUtils
. copyURLToFile ( new URL ( url
) , new File ( name
) ) ; } catch ( IOException e
) { e
. printStackTrace ( ) ; System
. out
. println ( "IO異常,downloader方法出現問題" ) ; } }
}
運行結果:
方法二:實現Runnable接口
定義類實現Runnable接口 實現run()方法,編寫線程執行體 創建線程對象,調用start()方法啟動線程
推薦使用Runnable接口,因為java單繼承的局限性
package com
. yxy
; public class ThreadDemo3 implements Runnable { @Override public void run ( ) { for ( int i
= 0 ; i
< 20 ; i
++ ) { System
. out
. print ( "run" + i
+ " " ) ; } } public static void main ( String
[ ] args
) { ThreadDemo3 threadDemo3
= new ThreadDemo3 ( ) ; new Thread ( threadDemo3
) . start ( ) ; for ( int i
= 0 ; i
< 20 ; i
++ ) { System
. out
. print ( "main" + i
+ " " ) ; } }
}
對比: 繼承Thread類 子類繼承Thread類具備多線程能力 啟動線程:子類對象.start() 不建議使用:避免OOP單繼承局限
實現Runnable接口: 實現接口Runnable具有多線程能力 啟動線程:傳入目標對象+Thread對象.start() 推薦使用:避免單繼承局限性,靈活方便,方便同一個對象被多個線程使用
栗子:多個線程同時操作同一個資源的情況下,線程不安全數據紊亂
package com
. yxy
;
public class ThreadDemo4 implements Runnable { private int ticketNums
= 10 ; @Override public void run ( ) { while ( true ) { if ( ticketNums
<= 0 ) { break ; } try { Thread
. sleep ( 200 ) ; } catch ( InterruptedException e
) { e
. printStackTrace ( ) ; } System
. out
. println ( Thread
. currentThread ( ) . getName ( ) + "---拿到了第" + ticketNums
-- + "張票" ) ; } } public static void main ( String
[ ] args
) { ThreadDemo4 threadDemo4
= new ThreadDemo4 ( ) ; new Thread ( threadDemo4
, "1" ) . start ( ) ; new Thread ( threadDemo4
, "2" ) . start ( ) ; new Thread ( threadDemo4
, "3" ) . start ( ) ; }
}
可能出現兩個線程拿到同一張票的情況
栗子:模擬龜兔賽跑
package com
. yxy
; public class Race implements Runnable { private static String winner
; @Override public void run ( ) { for ( int i
= 0 ; i
<= 100 ; i
++ ) { if ( Thread
. currentThread ( ) . getName ( ) . equals ( "兔子" ) && i
% 10 == 0 ) { try { Thread
. sleep ( 10 ) ; } catch ( InterruptedException e
) { e
. printStackTrace ( ) ; } } boolean flag
= gameOver ( i
) ; if ( flag
) { break ; } System
. out
. println ( Thread
. currentThread ( ) . getName ( ) + "--->跑了" + i
+ "步" ) ; } } private boolean gameOver ( int steps
) { if ( winner
!= null
) { return true ; } { if ( steps
== 100 ) { winner
= Thread
. currentThread ( ) . getName ( ) ; System
. out
. println ( "winner is " + winner
) ; return true ; } } return false ; } public static void main ( String
[ ] args
) { Race race
= new Race ( ) ; new Thread ( race
, "兔子" ) . start ( ) ; new Thread ( race
, "烏龜" ) . start ( ) ; }
}
方法三:實現Runnable接口(了解即可)
實現Callable接口,需要返回值類型
重寫call方法,需要拋出異常
創建目標對象
創建執行任務 ExecutorService ser = Executors.newFixedThreadPool(1);
提交執行 Future result1 = ser.submit(threadDemo1);
獲取結果 boolean rs1 = result1.get();
關閉服務 ser.shutdownNow();
package com
. yxy
. demo02
; import com
. sun
. org
. apache
. xpath
. internal
. operations
. Bool
;
import com
. yxy
. ThreadDemo2
;
import org
. apache
. commons
. io
. FileUtils
; import java
. io
. File
;
import java
. io
. IOException
;
import java
. net
. URL
;
import java
. util
. concurrent
. Callable
;
import java
. util
. concurrent
. ExecutorService
;
import java
. util
. concurrent
. Executors
;
import java
. util
. concurrent
. Future
; public class TestCallable implements Callable < Boolean> { private String url
; private String name
; public TestCallable ( String url
, String name
) { this . url
= url
; this . name
= name
; } @Override public Boolean
call ( ) throws Exception
{ WebDownLoader webDownLoader
= new WebDownLoader ( ) ; webDownLoader
. downloader ( url
, name
) ; System
. out
. println ( "下載了文件名為:" + name
) ; return true ; } public static void main ( String
[ ] args
) throws Exception
{ TestCallable threadDemo1
= new TestCallable ( "http://new-img3.ol-img.com/moudlepic/199_module_images/201707/5976d99c3d918_822.jpg" , "4.jpg" ) ; TestCallable threadDemo2
= new TestCallable ( "http://hzp.onlylady.com/qitamianbumeihu_index/filorga/pic_436152_1_1.html?imgUrl=http://p1.ol-cdn.com/product/100x100/5/437/5c6fa83739d64.jpg" , "5.jpg" ) ; TestCallable threadDemo3
= new TestCallable ( "http://hzp.onlylady.com/mianshuang_index/filorga/pic_436150_1_1.html?imgUrl=http://p1.ol-cdn.com/product/100x100/5/437/5c6fa724101a3.jpg" , "6.jpg" ) ; ExecutorService ser
= Executors
. newFixedThreadPool ( 1 ) ; Future
< Boolean> result1
= ser
. submit ( threadDemo1
) ; Future
< Boolean> result2
= ser
. submit ( threadDemo2
) ; Future
< Boolean> result3
= ser
. submit ( threadDemo3
) ; boolean rs1
= result1
. get ( ) ; boolean rs2
= result2
. get ( ) ; boolean rs3
= result3
. get ( ) ; System
. out
. println ( rs1
) ; System
. out
. println ( rs2
) ; System
. out
. println ( rs3
) ; ser
. shutdownNow ( ) ; } }
class WebDownLoader { public void downloader ( String url
, String name
) { try { FileUtils
. copyURLToFile ( new URL ( url
) , new File ( name
) ) ; } catch ( IOException e
) { e
. printStackTrace ( ) ; System
. out
. println ( "IO異常,downloader方法出現問題" ) ; } }
}
Callable的好處: 可以定義返回值 可以拋出異常
總結
以上是生活随笔 為你收集整理的线程的三种创建方式以及代码实现 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。