java高级-多线程编程
2019獨角獸企業重金招聘Python工程師標準>>>
一、進程和線程? ??????
????????在java語言中最大的特點就是支持多線程的開發(也是為數不多支持多線程開發的語言),如果對多線程沒有一個全面而且細致的了解,在以后一定存在嚴重的技術缺陷。
????? ? 進程:傳統的dos是單進程處理,允許一個程序執行,后來到了Windows時代,出現了多線程的設計。表示在一個時間段上可以運行多個程序,并且這些程序將進行資源的輪流搶占。在同一時間點上,只有一個程序執行,后來有了多核CPU的實現??梢詫崿F在同一時間點,多個程序同時執行。
????? ? 線程:是進程的基礎之上劃分的更小的程序單元,線程依賴于進程的實現,線程的啟動要比進程快的多。
二、Thread實現多線程
?范例:? 多線程主體類
class MyThread extends Thread{private String title;public MyThread(String title){this.title = title;}@Overridepublic void run() {for (int i = 0; i< 10; i++) {System.out.println(this.title+"運行,i="+i);}} }? ? 多線程要執行的功能都應該在run()方法中進行定義,run()方法不能被直接調用(如果我們直接調用子線程的run()方法,其方法還是運行在主線程中,代碼在程序中是順序執行的,所以不會有解決耗時操作的問題。所以不能直接調用線程的run()方法,只有子線程開始了,才會有異步的效果。當thread.start()方法執行了以后,子線程才會執行run()方法,這樣的效果和在主線程中直接調用run()方法的效果是截然不同的)。所以如果要開啟多線程,必須執行start()方法。
public static void main(String[] args) {new MyThread("線程A").start();new MyThread("線程B").start();new MyThread("線程C").start(); }? ?執行結果:線程A,B,C交替執行,執行順序不可控。
???結論:雖然調用是start()方法,但是最終執行的是run()方法。
? ?疑問:為什么不直接使用run()方法,而使用start()?
? ?start()源碼:
public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}} } private native void start0();? ? 分析start()方法源代碼:拋出“IllegalThreadStateException”異常,沒有throws也沒有try..catch,表明此異常一定是RuntimeException的子類。一個線程只允許啟動一次,否則就會拋出此異常。
? ? 列如:
public static void main(String[] args) {Thread t = new MyThread("線程A");t.start();t.start(); }? ? native含義:
? ? 在java執行過程中考慮到對于不同層次的開發者的需求,所以java支持有本地的操作系統函數調用,而這項技術成為JNI技術,但是Java開發過程中并不推薦這樣使用,這項技術可以使用一些底層函數進行一些特殊的處理,而在start()方法里面的start0()表示需要將此方法依賴于不同的操作系統實現。
三、Runnable接口實現多線程
范例:Runnable實現
class MyThread implements Runnable{private String title;public MyThread(String title){this.title = title;}@Overridepublic void run() {for (int i = 0; i< 10; i++) {System.out.println(this.title+"運行,i="+i);}} }? ? 此方式避免了單繼承的局限,也能更好的進行功能擴展。以后的開發中,優先考慮Runnable來實現,但是啟動多線程永遠都是通過Thread對象來啟動多線程。
????lambda表達式寫法:
public static void main(String[] args) {for (int i =0; i <3 ; i++){String title="線程對象_"+i;Runnable run=()->{for (int j = 0; j< 10; j++){System.out.println(title+"運行,j="+j);}};new Thread(run).start();}}更簡潔:
public static void main(String[] args) {for (int i =0; i <3 ; i++){String title="線程對象_"+i;new Thread(()->{for (int j = 0; j< 10; j++){System.out.println(title+"運行,j="+j);}}).start();}}四、Thread和Runnable的關系
? ? Thread也是Runnable接口的子類
? ? 關系圖:
????多線程的設計過程中,使用了代理模式,用戶自定義的MyThread的類只負責項目核心功能的實現嗎,而所有的輔助實現全部由Thread類來處理。
? ? 調用start()方法時候,通過Thread的構造函數傳遞了一個Runnable的接口對象,此對象將會被target保存,最終調用的將是Runnable子類覆蓋了Runnable接口的run()方法。
多線程開發示意圖:
范例:通過賣票程序來實現多個線程的資源并發訪問
class MyThread implements Runnable{private int ticket = 5;@Overridepublic void run() {for (int i = 0; i< 100; i++) {if(this.ticket> 0) {System.out.println("賣票,ticket=" + ticket--);}}} }public class Main {public static void main(String[] args) {MyThread mt = new MyThread();new Thread(mt).start();new Thread(mt).start();new Thread(mt).start();} }執行結果:
內存分析:
五、Callable實現多線程
????如果要實現多線程,肯定依靠的是Runnable,但是Runnable中的run()沒有返回值。所以JDK1.5后出現java.util.concurrent.Callable來實現多線程。
? ? 接口的定義:
@FunctionalInterface public interface Callable<V> {V call() throws Exception; }從定義可以發現Callable定義了一個泛型,此泛型的類型就是返回數據的類型,這樣的好處是避免向下轉型的安全隱患。
Callable的相關關系圖:
實例:Callable的線程實現
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask;class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {for(int i = 0; i< 10 ; i++){System.out.println("線程執行,i="+i);}return "程序執行完畢";} }public class Main {public static void main(String[] args) {try {FutureTask<String> task = new FutureTask<>(new MyThread());new Thread(task).start();System.out.println("【線程返回數據】"+task.get());}catch(Exception e){e.printStackTrace();}} }執行結果:
注:Runnable和Callable的區別?
1.Runnable是在JDK1.0的時候提出的多線程的實現接口,而Callable是在JDK1.5以后提出的。
2.java.util.Runnable接口只有一個run()方法,沒有返回值,java.util.concurrent.Callable接口里面只有一個call()方法,可以有返回值。
六、線程的運行狀態
對于多線程的開發而言,總是先定義線程主題類,通過Thread進行線程的啟動,當你調用start()方法并不意味著線程已經啟動。
線程的運行狀態:
1.任何一個線程對象都應該使用Thread來進行封,并且通過start()進行啟動,啟動的時候,線程就會進入一種就緒狀態,并沒有執行。
2.進入到就緒狀態后,就需要等待資源調度,當某一個線程調度成功后進入運行狀態(run()),但是所有的線程不可能一直持續的執行下去,中間需要產生一些暫停的狀態。例如:某個線程執行一段時間后讓出資源,而后,這個線程就將進入阻塞狀態。隨后重新回到就緒狀態。
3.當run()方法執行完畢后,線程的主要任務也就完成了,此時就可以進入停止狀態。
轉載于:https://my.oschina.net/chenzhou/blog/2049677
總結
以上是生活随笔為你收集整理的java高级-多线程编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: centos7配置不开启浏览器执行基于p
- 下一篇: Open vSwitch系列实验(一):