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