Java多线程(1)—线程初探
一、引言
? ? ? ?說到線程,經常會聽到線程同步,首先是為什么要線程同步?什么是線程同步?
因為當有多個線程要同時訪問一個變量或對象時,如果這些線程的執行(比如既有讀又有寫操作)時,就會導致變量值或對象的狀態出現混亂,從而導致程序異常。這里以在銀行賬戶取錢為例,工行的卡里有¥3000,此時微信和支付寶做查詢的時候,均顯示3000元,如果微信支付2000,支付寶支付2000
?
?
?
?
這里就會使用到多線程。在使用之前先了解下多線程的的知識
什么時候需要使用到多線程?
程序需要同時執行兩個或者多個任務時,如用戶輸入,文件讀寫等。Java語言的JVM運行程序運行多個線程,通過java.lang.Thread類來實現。
Thread有如下的特性:
- 每個線程都是通過某個特定的 Thread對象的run()方法來完成操作的,?經常把run()的主體稱為線程體
- 通過Thread類的start()方法來調用這個線程
因此想要在開啟的多線程中運行代碼邏輯,就寫在run()即可。Thread有如下的構造函數
Thread();//創建Thread對象 Thread(String threadName);//創建線程并指定線程實例名稱 Thread(Runnable target);//指定創建線程的目標對象,它實現了Runnable接口中的run方法 Thread(Runnable target,String name);//創建新的Thread對象1、線程創建
而創建線程通常有兩種方式:
1.1、繼承Thread類
1)定義子類繼承Thread類
2)子類中重寫Thread類的run方法
3)創建Thread子類對象,即創建線程對象
4)調用線程對象start()方法,啟動線程,調用run()方法
先看一下Test.java
package blog;public class Test {public static void main(String[] args) {Thread t0 = new TestThread();t0.start();//主線程System.out.println("主線程========");System.out.println("主線程========");System.out.println("主線程========");} }繼承Thread的子類為TestThread.java
package blog;public class TestThread extends Thread{@Overridepublic void run() {// TODO Auto-generated method stub//super.run();System.out.println("運行多線程的代碼");for (int i = 0; i < 5; i++) {System.out.println("多線程邏輯 : " + i);}} }這里不會給出上述的運行結果,因為每次運行可能輸出結果不同。這是因為在mian中執行t0.start()就開啟了多線程,這個時候t0.start()之后的main方法中的其他代碼的運行和就run方法的運行沒有關聯了。因此控制臺輸出的結果為子線程輸出結果和main中的輸出結果的并集,且順序不確定,但是各自回保持各自的先后順序關系。這個就是多線程。
當然這里還可以繼承新開新的線程
Thread t0 = new TestThread(); t0.start();Thread t1 = new TestThread(); t1.start();1.2、實現Runnable接口
1)定義子類實現Runnable接口
2)子類中重寫Runnable接口中的run方法
3)創建Thread類含參構造器創建線程對象
4)將Runnable接口的子類對象作為實際參數傳遞給Thread類的構造方法
5)調用線程對象start()方法,啟動線程,調用Runnable子類的run()方法
先在TestRunnable.java子類中實現Runnable接口
public class TestRunnable implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("運行多線程的代碼");for (int i = 0; i < 5; i++) {System.out.println("Runnable多線程邏輯 : " + i);}}}同樣在main中,創建對象,
這里有個Runnable實例
package blog;public class Test {public static void main(String[] args) {Thread t3 = new Thread(new TestRunnable());t3.start();//主線程System.out.println("主線程========");System.out.println("主線程========");System.out.println("主線程========");} }同樣在上述的創建對象的過程還有一個兩個參數的構造函數,Thread(Runnable target,String name),這里的name指定為線程的名稱。注意這里使用的是new TestRunnable()匿名對象。
先將TestRunnable.java中的輸出語句修改為:
System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + i);這里的Thread.currentThread().getName()就是獲取當前線程名稱,輸出對比發現,未設置的默認為Thread-0:
那這個有個命名有什么用呢,當然是可以查看多線程的之間的異步調用次序
既然實現多線程有這兩種方式,那使用哪個呢?
2、多線程實現兩種方式的區別
推薦使用實現Runnable的方式
- 繼承Thread,線程代碼存放在Thread子類run方法中,重新run()方法
- 實現Runnable,線程代碼存在在實現接口子類的run()方法中,實現run()方法
實現接口的好處:
1)避免了單接口的限制
2)多個線程可以共享同一個接口實現類的對象,非常適合多個相同線程來處理同一份資源。
將上述代碼修改下,就能體現出來Runnable實現的子類的作用。
package blog;public class TestRunnable implements Runnable{private int count = 0;@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("運行多線程的代碼");for (int i = 0; i < 5; i++) {count ++;System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + count);}}}在main改造如下所示
t4和t5共同處理的是TestRunnable中的資源,count
3、Thread常用方法
3.1、線程啟動設置
void start()啟動線程,并執行run()方法
run()線程在被調度時執行的操作
String getName()返回線程的名稱
static currentThread()返回當前線程
package blog;public class TestRunnable {public static void main(String[] args) {TestRun run0 = new TestRun();TestRun run1 = new TestRun();Thread t0 = new Thread(run0);Thread t1 = new Thread(run1);t0.start();t1.start();t0.setName("線程-t0");System.out.println(t0.getName());//如果沒有設置線程名稱,則系統會給出系統默認名稱,為Thread-NSystem.out.println("主線程========");System.out.println("主線程========");}}class TestRun implements Runnable{private int count = 0;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " :運行多線程的代碼");for (int i = 0; i < 5; i++) {count ++;System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + count);}} }輸出結果如下:
?
3.2、線程優先級設置
getPriority() 返回線程優先級
setPriority(int newPriority) 設置線程優先級,范圍為[1,10]數字越大優先級約到,默認為5,設置較大優先級表示當前線程有較大概率被優先執行
?
從輸出結果來看,并不是設置了最高優先級就一定是最先獲得資源并進行執行,所以這里說的的有較高概率去執行
3.3、線程讓步yield
讓步顧名思義,就是“讓給他人”,暫停當前正在執行的線程,把執行機會讓給優先級相同的或者優先級更高的線程;若隊列中沒有相同優先級的線程,則忽略此步驟。
package blog;public class TestRunnable {public static void main(String[] args) {TestRun run0 = new TestRun();TestRun run1 = new TestRun();Thread t0 = new Thread(run0);Thread t1 = new Thread(run1);t0.start();t1.start();System.out.println(t0.getName());//如果沒有設置線程名稱,則系統會給出系統默認名稱,為Thread-NSystem.out.println("主線程========");System.out.println("主線程========");}}class TestRun implements Runnable{private int count = 0;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " :運行多線程的代碼");for (int i = 0; i < 5; i++) {if(i % 2 == 0)Thread.yield();//線程讓步count ++;System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + count);}} }在run()方法中,通過判斷循環是否為偶數,來實現讓線程讓步。
3.4、線程阻塞
當某個程序執行流中調用其他線程的join()方法時,調用線程將被阻塞,直到join()方法加入的join線程執行完成。通俗的說就是調用join的線程做了一次插隊的操作,見如下所示
package blog;public class TestRunnable {public static void main(String[] args) {TestRun run0 = new TestRun();TestRun run1 = new TestRun();Thread t0 = new Thread(run0);Thread t1 = new Thread(run1);t0.start();t1.start();System.out.println("主線程========1");System.out.println("主線程========2");try {t0.join();//相當于把t0.run的代碼插入到此處進行執行} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("主線程========3");}}class TestRun implements Runnable{private int count = 0;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " :運行多線程的代碼");for (int i = 0; i < 5; i++) {count ++;System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + count);}} }輸出結果如下:
3.5、線程睡眠與結束?
@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " :運行多線程的代碼");for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}count ++;System.out.println(Thread.currentThread().getName() + " :Runnable多線程邏輯 : " + count);}}強制結束線程使用t0.stop()即可,使用很少,這里不再贅述。
4、線程生命周期與狀態
介紹了上面這么的線程的常用方法,那調用了對應的方法達到了什么樣的線程狀態呢?
總結
以上是生活随笔為你收集整理的Java多线程(1)—线程初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java面向对象特征介绍
- 下一篇: Java多线程(2)—线程同步