摘要:多線程的實(shí)現(xiàn)用多線程只有一個(gè)目的更好的利用資源燒水的例子當(dāng)洗杯子花分鐘線程要停分鐘等待返回結(jié)果才能進(jìn)行后續(xù)的燒水操作,新開一個(gè)線程執(zhí)行洗杯子操作。指在并發(fā)的情況之下,該代碼經(jīng)過多線程使用,線程的調(diào)度順序不影響任何結(jié)果。
Java多線程的實(shí)現(xiàn)
用多線程只有一個(gè)目的:更好的利用cpu資源.燒水的例子.(當(dāng)洗杯子花5分鐘,線程要停5分鐘等待返回結(jié)果才能進(jìn)行后續(xù)的燒水操作,新開一個(gè)線程執(zhí)行洗杯子操作)。
一、關(guān)于線程的一些概念
cpu時(shí)間片:我們操作系統(tǒng)看起來可以多個(gè)程序同時(shí)運(yùn)行.分時(shí)操作系統(tǒng),將時(shí)間分成長短相同的時(shí)間區(qū)域,分配給一個(gè)線程使用,當(dāng)線程還沒有結(jié)束,時(shí)間片已經(jīng)過去,該線程只有先停止,等待下一個(gè)時(shí)間片.cpu運(yùn)行很快,中間的停頓感覺不出來.
多線程:指的是這個(gè)程序(一個(gè)進(jìn)程)運(yùn)行時(shí)產(chǎn)生了不止一個(gè)線程(比如,下載程序,開啟多個(gè)線程同時(shí)進(jìn)行.)
并行:多個(gè)cpu實(shí)例或者多臺(tái)機(jī)器同時(shí)執(zhí)行一段處理邏輯,是真正的同時(shí)。
并發(fā):通過cpu調(diào)度算法,讓用戶看上去同時(shí)執(zhí)行,實(shí)際上從cpu操作層面不是真正的同時(shí)。并發(fā)往往在場景中有公用的資源,那么針對這個(gè)公用的資源往往產(chǎn)生瓶頸,我們會(huì)用TPS或者QPS來反應(yīng)這個(gè)系統(tǒng)的處理能力.
線程安全:經(jīng)常用來描繪一段代碼。指在并發(fā)的情況之下,該代碼經(jīng)過多線程使用,線程的調(diào)度順序不影響任何結(jié)果。這個(gè)時(shí)候使用多線程,我們只需要關(guān)注系統(tǒng)的內(nèi)存,cpu是不是夠用即可。反過來,線程不安全就意味著線程的調(diào)度順序會(huì)影響最終結(jié)果.
Java中的同步指的是通過人為的控制和調(diào)度,保證共享資源的多線程訪問成為線程安全,來保證結(jié)果的準(zhǔn)確。如上面的代碼簡單加入@synchronized關(guān)鍵字。在保證結(jié)果準(zhǔn)確的同時(shí),提高性能,才是優(yōu)秀的程序。線程安全的優(yōu)先級(jí)高于性能.
二、Java多線程的實(shí)現(xiàn)
1、繼承Thread類創(chuàng)建線程
Thread類本質(zhì)上是實(shí)現(xiàn)了Runnable接口,啟動(dòng)該線程的唯一方法是start()方法,
public class MyThread extends Thread{ //普通的調(diào)用方法,定義任務(wù)要完成的工作. @Override public void run() { System.out.println("新線程正在執(zhí)行,處理相關(guān)的邏輯!"); } } public class Test { public static void main(String[] args) { //實(shí)例化對象 MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); //開啟新的線程,分配新的資源 myThread1.start(); myThread2.start(); } }
2、實(shí)現(xiàn)Runnable接口創(chuàng)建線程
java中是單繼承的,如果繼承了一個(gè)類,就不能直接繼承Thread類,需要實(shí)現(xiàn)Runnable接口的方式達(dá)到開啟新線程的目的.
public class MyThread implements Runnable { //普通的調(diào)用方法,定義任務(wù)要完成的工作. @Override public void run() { System.out.println("新線程正在執(zhí)行,處理相關(guān)的邏輯!"); } } public class Test { public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread =new Thread(myThread); //開啟新的線程,分配新的資源 thread.start(); } }
3、實(shí)現(xiàn)Callable接口
Callable接口的call()方法類似run()方法,都是定義任務(wù)要完成的工作.主要不同點(diǎn)是call()方法是有返回值的、可以拋出異常。Callable類型的任務(wù)可以有兩種方法開啟執(zhí)行.
方法一:借助FutureTask執(zhí)行(FutureTask、Callable)
將Callable接口對象放到FutureTask對象中,F(xiàn)utureTask的get()方法,可以獲取返回值.
public class MyCallableTask implements Callable{ @Override public Integer call() throws Exception { System.out.println("新線程正在執(zhí)行,處理相關(guān)的邏輯!"); Thread.sleep(3000); int sum = 0; for(int i=0;i<100;i++) { sum += i; } return sum; } } public class Test { public static void main(String[] args) { Callable mycallabletask = new MyCallableTask(); //由Callable 創(chuàng)建一個(gè)FutureTask 對象: FutureTask futuretask = new FutureTask (mycallabletask); //注釋:FutureTask 是一個(gè)包裝器,它通過接受Callable 來創(chuàng)建,它同時(shí)實(shí)現(xiàn)了Future 和Runnable接口。 //由FutureTask 創(chuàng)建一個(gè)Thread對象: Thread oneThread = new Thread(futuretask); oneThread.start(); try { //通過futuretask中g(shù)et()方法可以得到MyCallableTask的call()運(yùn)行結(jié)果. //需要使用時(shí)獲取出來,否則出現(xiàn)堵塞,本線程要等待新線程執(zhí)行完返回結(jié)果才執(zhí)行 Integer i = futuretask.get(); } catch (Exception e) { e.printStackTrace(); } } }
方法二:借助線程池來運(yùn)行 (ExecutorService、Callable、Future)
ExecutorService、Callable、Future三個(gè)接口實(shí)際上都是屬于Executor框架。
執(zhí)行Callable任務(wù)后,可以獲取一個(gè)Future的對象,在該對象上調(diào)用get()就可以獲取到Callable任務(wù)返回的Object了。
public class MyCallableTask implements Callable{ @Override public Integer call() throws Exception { System.out.println("新線程正在執(zhí)行,處理相關(guān)的邏輯!"); Thread.sleep(3000); int sum = 0; for(int i=0;i<100;i++) { sum += i; } return sum; } } public class Test { public static void main(String[] args) { int taskSize = 5; //創(chuàng)建線程池 ExecutorService threadPool = Executors.newCachedThreadPool(taskSize); //提交一個(gè)Callable任務(wù),返回一個(gè)Future類型 Future future = threadPool.submit(new MyCallableTask()); try { Thread.sleep(3000);//模擬本線程的一些任務(wù) //獲取執(zhí)行結(jié)果get方法是阻塞的 System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); } } }
采用匿名類直接新建Callable接口
public class Test{ public static void main(String[] args) { // 創(chuàng)建線程池 ExecutorService threadPool = Executors.newCachedThreadPool(); // 提交一個(gè)Callable任務(wù),返回一個(gè)Future類型 Futurefuture = threadPool.submit(new Callable () { @Override public Integer call() throws Exception { System.out.println("新線程正在執(zhí)行,處理相關(guān)的邏輯!"); Thread.sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }); try { Thread.sleep(3000);//模擬本線程的一些任務(wù) //獲取執(zhí)行結(jié)果 System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); } } }
三、使用場景
一、Tomcat內(nèi)部采用了多線程,上百個(gè)用戶同時(shí)訪問同一個(gè)web應(yīng)用,都會(huì)新開一個(gè)線程,調(diào)用到Servlet程序。如果不使用多線程,將串行操作,客戶端將等待別人執(zhí)行完才能訪問。
二、異步請求,有兩個(gè)任務(wù)Task a和Task b,單線程只能先進(jìn)行a再進(jìn)行b。
三、需要知道執(zhí)行進(jìn)度,比如說我們常看到的進(jìn)度條,任務(wù)執(zhí)行到一定進(jìn)度給new 一個(gè)變量,給變量+1.新開一個(gè)線程去輪詢這個(gè)變量,反饋給客戶端,這樣就可以看到進(jìn)度情況.
總之,很多地方都用到了多線程,多線程是為了充分利用cpu資源,當(dāng)你發(fā)現(xiàn)一個(gè)業(yè)務(wù)邏輯執(zhí)行效率特別低,耗時(shí)長,可以考慮使用多線程.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69185.html
摘要:多線程環(huán)境下的一些問題安全性問題在沒有正確同步的情況下,多線程環(huán)境下程序可能得出錯(cuò)誤的結(jié)果。一些相關(guān)概念競爭條件多線程的環(huán)境下,程序執(zhí)行的結(jié)果取決于線程交替執(zhí)行的方式。而線程的交替操作順序是不可預(yù)測的,如此程序執(zhí)行的結(jié)果也是不可預(yù)測的。 入口 Java多線程的應(yīng)用復(fù)雜性之如jvm有限的幾個(gè)內(nèi)存方面的操作和規(guī)范,就像無數(shù)紛繁復(fù)雜的應(yīng)用邏輯建立在有限的指令集上。 如何寫出線程安全的程序,有...
摘要:線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...
摘要:相比與其他操作系統(tǒng)包括其他類系統(tǒng)有很多的優(yōu)點(diǎn),其中有一項(xiàng)就是,其上下文切換和模式切換的時(shí)間消耗非常少。因?yàn)槎嗑€程競爭鎖時(shí)會(huì)引起上下文切換。減少線程的使用。很多編程語言中都有協(xié)程。所以如何避免死鎖的產(chǎn)生,在我們使用并發(fā)編程時(shí)至關(guān)重要。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)syn...
摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握J(rèn)ava多線程基礎(chǔ)知識(shí)來對應(yīng)日后碰到的問題。(...
摘要:因?yàn)槎嗑€程競爭鎖時(shí)會(huì)引起上下文切換。減少線程的使用。舉個(gè)例子如果說服務(wù)器的帶寬只有,某個(gè)資源的下載速度是,系統(tǒng)啟動(dòng)個(gè)線程下載該資源并不會(huì)導(dǎo)致下載速度編程,所以在并發(fā)編程時(shí),需要考慮這些資源的限制。 最近私下做一項(xiàng)目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項(xiàng)目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Jav...
摘要:系統(tǒng)級(jí)線程核心級(jí)線程由操作系統(tǒng)內(nèi)核進(jìn)行管理。值得注意的是多線程的存在,不是提高程序的執(zhí)行速度。實(shí)現(xiàn)多線程上面說了一大堆基礎(chǔ),理解完的話。虛擬機(jī)的啟動(dòng)是單線程的還是多線程的是多線程的。 前言 之前花了一個(gè)星期回顧了Java集合: Collection總覽 List集合就這么簡單【源碼剖析】 Map集合、散列表、紅黑樹介紹 HashMap就是這么簡單【源碼剖析】 LinkedHashMa...
閱讀 2978·2021-11-23 09:51
閱讀 3609·2021-10-13 09:39
閱讀 2493·2021-09-22 15:06
閱讀 881·2019-08-30 15:55
閱讀 3147·2019-08-30 15:44
閱讀 1778·2019-08-30 14:05
閱讀 3434·2019-08-29 15:24
閱讀 2362·2019-08-29 12:44