我12月份怎么找不到了(十二月沒有奇跡)
724
2022-05-29
前兩篇博客我寫了有關創建線程以及創建線程池的方法,這篇博客用來總結JAVA多線程實戰第一章創建線程的其他內容,一些創建和使用線程的知識點。
一、Thread類和Runnable接口的區別
之前講的創建線程的四種方法中前兩中方法分別是通過繼承Thread類和實現Runnable接口創建線程,這兩種方法是創建線程的最常用方法,那兩者有什么區別?
直接通過代碼演示。
public class MyThread extends Thread{ private int ticket = 10; public MyThread(String name) { super(name); } @Override public void run() { while(true) { if(ticket>0) { System.out.println(Thread.currentThread().getName()+"賣出第"+(10-ticket--+1)+"張門票"); } } } } public class MyThreadTest { public static void main(String[] args) { // TODO Auto-generated method stub MyThread mt1 = new MyThread("窗口一"); MyThread mt2 = new MyThread("窗口二"); MyThread mt3 = new MyThread("窗口三"); mt1.start(); mt2.start(); mt3.start(); } }
public class MyRunnable implements Runnable{ private int ticket = 10; @Override public void run() { // TODO Auto-generated method stub while(true) { if(ticket>0) { System.out.println(Thread.currentThread().getName()+"賣出"+(10- ticket-- +1)+"張票"); } } } } public class MyRunnableTest { public static void main(String[] args) { // TODO Auto-generated method stub MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr,"窗口一"); Thread t2 = new Thread(mr,"窗口二"); Thread t3 = new Thread(mr,"窗口三"); t1.start(); t2.start(); t3.start(); } }
繼承Thread類創建線程的運行結果是三個線程獨立進行,不共享資源。所以可知,這種方法創建線程不共享資源
實現Runnable接口的運行結果是三個線程共享資源,可以把Runnable當成資源,多線程共享資源
二、線程start和run方法的區別
通過代碼演示
public class UseThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+",執行run方法"); } } public class UserThreadTest { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()+" 執行main方法"); UseThread useThread = new UseThread(); useThread.run();//只有一個線程再執行,是單線程的 useThread.start();//創建一個新線程 } }
根據運行結果可以看出,使用run()方法時,程序是單線程,只有主線程main在執行任務,run()方法的內容也是有主線程執行,并沒有新建線程執行run()方法
使用start()方法后,run()方法里的內容被新建的線程執行。
所以如果想新建線程,那就要用start()方法
三、線程的優先級
JAVA默認情況下線程是有輪流使用CPU的特權,平均分配給每個線程占用CPU的使用時間,但是設置優先級后就不一樣了
有關線程優先級的知識點
Java的優先級是從1-10,默認優先級是5,10最高。
主線程main的優先級是5
優先級高的線程占用CPU的概率大,但是優先級低的線程并不是沒有機會執行,只是概率問題
即使設置了優先級,也無法保證線程的執行順序,只是概率問題
public class UserRunnable implements Runnable{ @Override public void run() { for(int i = 0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"第"+i+"次執行"); } } } public class UserThread extends Thread{ @Override public void run() { for(int i = 0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"第"+i+"次執行"); } } } public class Test { public static void main(String[] args) { // TODO Auto-generated method stub UserThread ut = new UserThread(); UserRunnable ur = new UserRunnable(); Thread t = new Thread(ur); ut.setPriority(1); t.setPriority(10); ut.start(); t.start(); } }
四、定時線程的任務調度
調用定時線程有兩種方法,分別是schedule()和scheduleAtFixedRate(),兩者區別是前者特點為延時不追加執行任務,后者特點為延時追加任務。這兩個特點的含義是什么呢?
延時不追加任務:當前系統時間已經超過了設置時間,線程從當前時間執行任務。當前時間沒到設置時間,線程會等時間到了再執行任務
延時追加任務:當前系統時間已經超過了設置時間,線程會將當前時間和設置時間組差,根據設置的任務執行間隔算出少執行多少次人物,補充之前少的執行結果
五、接口同步回調和異步回調
同步調用:一種阻塞式調用,調用方要等待對方執行完才能返回,它是一種單向調用,平時我們調用方法就是同步調用
回調:一種雙向調用模式,被調用方在接口被調用時也會調用對方接口
異步調用:一種類似事件或消息機制,不過他的調用方向剛好相反,接口的服務在接收到某種訊息或者發生某種事件會主動通知客戶端。不需要等待對方執行完再返回
第一種情況
public interface Callback { public void process(String msg); } public class MyCallback implements Callback{ @Override public void process(String msg) { // TODO Auto-generated method stub System.out.println("處理成功,返回狀態為: "+msg); } }//這個方法就是回調函數,客戶端給服務端輸入信息,通過回調函數告知客戶端信息已被處理 public class Server { public void getMsg(Callback callback,String msg) throws InterruptedException { System.out.println("服務器端已接收到信息:"+msg); //模擬消息處理,等待兩分鐘 Thread.sleep(2000); System.out.println("消息已經被處理,返回狀態為:"+msg); //處理完消息,調用客戶端,已經處理好消息 callback.process(msg); }//獲取服務器端消息并且對消息進行處理,再告訴客戶端你的消息已經被處理成功了 } public class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(String msg) throws InterruptedException { System.out.println("客戶端發出消息:"+msg); server.getMsg(new MyCallback(), msg); System.out.println("客戶端已發出,等待處理"); } } public class Test1 { public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Server s = new Server(); Client c = new Client(s); c.sendMsg("200"); } }
這種就是調用方法,也就是同步回調,輸出結果如下:
客戶端發出消息:200
服務器端已接收到信息:200
消息已經被處理,返回狀態為:200
處理成功,返回狀態為: 200
客戶端已發出,等待處理
可以看出這個輸出結果的順序不是我們想要的,因為程序在等getMsg執行完才會往下執行
解決方法,在客戶端創建線程是
public class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(String msg) throws InterruptedException { System.out.println("客戶端發出消息:"+msg); // server.getMsg(new MyCallback(), msg); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start();; System.out.println("客戶端已發出,等待處理"); } }
這次的執行結果就符合預期
客戶端發出消息:200
客戶端已發出,等待處理
服務器端已接收到信息:200
消息已經被處理,返回狀態為:200
處理成功,返回狀態為: 200
創建線程后就各干各的,不用等一個做完才能做下一個
六.總結
好啦,第一章全部總結完畢,希望能給其他學習java的伙伴帶來一定關注,后續還會繼續更新
Java 培訓服務
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。