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