JavaEE初階:多線程 - 編程

1.認識線程

我們在之前認識了什么是多進程,今天我們來了解線程。

一個線程就是一個 "執行流". 每個線程之間都可以按照順訊執行自己的代碼. 多個線程之間 "同時" 執行 著多份代碼.

引入進程這個概念,主要是為了解決并發編程這樣的問題。因為cpu進入了多核心的時代,要想進一步提高程序的執行速度,就需要充分的利用CPU的多核資源。

其實多進程編程,已經可以解決并發編程的問題了,它已經可以利用起來cpu多核資源了,但是問題是:
進程太重了(消耗資源多、速度慢)

創建一個進程,開銷比較大。

銷毀一個進程,開銷也比較大。? ? ? ? ? ?

調度一個進程,開銷還比較大。

說進程重,主要就是重在資源分配/回收上。

線程應運而生,線程也叫做"輕量級進程",
解決并發編程問題的前提下,讓創建,銷毀,調度的速度更快一些
線程為啥更"輕",把申請資源/釋放資源的操作給省下了。

1.1 進程和線程的區別

進程是包含線程的。每個進程至少有一個線程存在,即主線程。

進程和進程之間不共享內存空間。同一個進程的線程之間共享同一個內存空間。

進程是系統分配資源的最小單位,線程是系統調度的最小單位。

光靠文字可能有點抽象,我們舉個例子:

多進程:

?多線程:

在多進程中,啟用了兩套院子,那么啟用的成本是比較大的,耗費的時間也是比較多的,但是在第二套中,院子和運輸材料的通道都是公用的,那么就節省了成本。

在啟動一個新的生產線時,就不需要重新啟動一個院子,而是在原來的院子里啟用,節省了許多的成本。

線程和進程的關系,是進程包含線程,
一個進程可以包含一個線程,也可以包含多個線程,但是不能沒有。

對比下來,主要的優勢在于:


只有第一個線程啟動的時候,開銷是比較大的,但是后續線程就省事了.,不論是啟動還是關閉,耗費的資源都比啟動/關閉一個進程要小。

同一個進程里的多個線程之間,共用了進程的同一份資源(主要指的是內存和文件描述符表)。這樣這一部分資源就不需要重新啟動或關閉。

操作系統,實際調度的時候,是以線程為單位進行調度的。

之前介紹的,,PCB里的狀態,上下文,優先級,記賬信息,都是每個線程有自己的。各自記錄各自的但是同一個進程里的PCB之間, ,pid是一樣的,內存指針和文件描述符表也是一樣的。

那么既然線程這么好,可不可以無限制的在一個進程中增加線程呢?

并不可以,線程如果太多,核心數量有限,那么不少的開銷就會浪費在線程調度上了,但是在多進程中就不會出現這樣的狀況。

線程模型,天然就是資源共享的.多線程爭搶同一個資源(同一個變量)非常容易觸發的.
進程模型,天然是資源隔離的.不容易觸發.進行進程間通信的時候,多個進程訪問同一個資源,可能會出問題.

?

1.2 多線程編程

本身關于線程的操作,操作系統提供的API,我們只需要學習Java提供的API就好了。

Java操作多線程,最核心的類 :Thread?

先在src下創建一個包,接著再創建一個類?

創建好主函數后,我們新建一個Thread的對象

Thread t = new Thread();

但是我們還需要一個類,新建一個Mythread類,并且重寫run方法

class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}

然后在main中,開始啟動一個特殊的方法:

t.start;

完整的代碼:

class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("hello main");}
}

這樣一個代碼,就新啟動了一個線程,使得打印hello world和打印hello main是以完全不同的方式來完成的。

start這里的工作,就是創建了一個新的線程,新的線程負責執行重寫過后的t.run。

具體的執行方法,就是start這個方法會調用操作系統的API,通過操作系統內核創建新線程的PCB,并且把要執行的指令交給PCB,當PCB被調度到CPU上執行的時候,也就執行到了線程run方法中的代碼了。


通過具體的結果,,兩個線程是同時進行的,并且可以看做是一次運行時無序,可能先打印world,也可能先打印main。

但是運行的時候不一定誰先誰后,
操作系統調度線程的時候,"搶占式執行",具體哪個線程先上,哪個線程后上,不確定,取決于操作系統調度器具體實現策略.
雖然有優先級,但是在應用程序層面上無法修改.
從應用程序(代碼)的角度,看到的效果,就好像是線程之間的調度順序是"隨機"的一樣.

內核里本身并非是隨機.但是干預因素太多,并且應用程序這一層也無法感知到細節,就只能認為是隨機的了。
為啥會有線程安全問題?罪魁禍首,萬惡之源,就是這里的搶占式執行,隨機調度。

start和run的區別

start是真正創建了一個線程(從系統這里創建的),線程是獨立的執行流。


run 只是描述了線程要干的活是啥,如果直接再main中調用run,此時沒有創建新線程,全是main線程一個人干活。相當于還是單線程。

可以使用jdk自帶的工具jconsole查看當前的java進程中的所有線程.?


????????


這里面就可以看到進程。同時進程中還有很多個線程。除了我們使用的,其他的都是JVM自帶的

?

?1.3 多線程的五種創建方法

1.繼承Thread,重寫run方法

class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("hello main");}
}

也就是上面詳細介紹的方法。

2.實現 Runnable 接口

class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("hello thread");}
}
public class ThreadDemo2 {public static void main(String[] args) {Runnable runnable = new MyRunnable();Thread t = new Thread(runnable);t.start();}
}

Runnable 作用,是描述一個“要執行的任務”,然后把這個任務交給Thread來執行。

好處就是這樣寫可以解耦合,讓線程和線程之間干的活要分開。

3.使用匿名內部類,繼承 Thread

public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {System.out.println("hello");}};t.start();}
}

這里面創建了一個Thread的子類,并且創建了子類的實例,讓 t 引用指向該實例。

4.使用匿名內部類,實現 Runable

public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("hello demo4");}});t.start();}
}

這個寫法和2本質相同,只不過是把Runnable任務交給匿名內部類的語法。

此處是創建了一個類,實現Runnable,同時創建了類的實例,并且傳給Thread的構造方法。

5.使用 Lambda 表達式(推薦)

public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello demo5");});t.start();}
}

使用lambda表達式來描述,直接把lambda傳給Thread構造方法。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39099.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39099.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39099.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

編譯工具:CMake(三)| 最簡單的實例升級

編譯工具:CMake(三)| 最簡單的實例升級 前言過程語法解釋ADD_SUBDIRECTORY 指令 如何安裝目標文件的安裝普通文件的安裝:非目標文件的可執行程序安裝(比如腳本之類)目錄的安裝 修改 Helloworld 支持安裝測試 前言 本篇博客的任務…

utf-8和utf-8 mb4區別

UTF-8(Unicode Transformation Format-8)和UTF-8MB4(UTF-8 Multibyte 4-byte)是字符編碼方案,用于表示 Unicode 字符集中的字符。它們之間的主要區別在于編碼范圍。 UTF-8:UTF-8 是一種變長編碼方式&#x…

可視化繪圖技巧100篇進階篇(七)-三維堆積柱形圖(3D Stacked Bar Chart)

目錄 前言 適用場景 圖例 繪圖工具及代碼實現 HighCharts echarts MATLAB

學習Vue:安裝Vue.js和設置開發環境

當您決定進入現代前端開發的世界,Vue.js 無疑是一個令人激動的選擇。它以其簡潔、靈活和高效的特點在開發者社區中備受贊譽。本文將為您詳細介紹如何安裝 Vue.js 并設置開發環境,讓您能夠迅速開始編寫 Vue 應用程序。 步驟1:安裝 Node.js 和 …

解決右鍵打印html只能識別1頁的問題

hello,大家好久不見,昨天在開發中遇到了一個問題,就是在自己開發的網頁中右鍵-->打印,由于頁面內容過多,打印出來的內容只被識別到一頁。 針對這一問題,查閱了好多資料最終解決啦。 1.問題重現 大家可以看到這個是我們開發的頁面,公司需要…

CentOS系統環境搭建(六)——使用docker-compose安裝redis

centos系統環境搭建專欄🔗點擊跳轉 關于Docker-compose安裝請看CentOS系統環境搭建(三)——Centos7安裝Docker&Docker Compose,該文章同樣收錄于centos系統環境搭建專欄。 Docker-compose安裝redis 文章目錄 Docker-compose安…

2023最新最全最細版本~ESP8266/ESP01S燒錄AT固件

硬件準備 圖上有兩種型號的模塊均可刷寫AT固件 ① ESP01S ② ESP8266NODEMCU 軟件準備(私聊免費分享) ESP01S1燒錄方式 如圖使用模塊燒錄座的方式~ 模塊插入燒錄座后直接連接電腦的USB接口即可~ ESP8266NODEMCU燒錄方式 如圖usb直接連接的方式~ 一端接模塊的USB口&…

數據暴漲時代,該如何數據治理?_光點科技

隨著信息技術的迅猛發展,數據已經成為現代社會的核心資源。在這個被稱為"數據暴漲時代"的時代里,大量的數據源源不斷地被產生和積累,但如何有效地管理、分析和利用這些數據成為了一個迫切需要解決的問題。數據治理,作為…

【Spring源碼】Spring擴展點及順序

Spring擴展點及順序 01-調用BeanFactoryPostProcessor的構造器 02-調用了BeanFactoryPostProcessor的postProcessBeanFactory 03-調用了BeanPostProcessor構造器 04-調用InstantiationAwareBeanPostProcessor構造方法 05-調用了InstantiationAwareBeanPostProcessor接口的Befo…

Memory Analyzer(MAT)分析內存

關于作者:CSDN內容合伙人、技術專家, 從零開始做日活千萬級APP。 專注于分享各領域原創系列文章 ,擅長java后端、移動開發、人工智能等,希望大家多多支持。 目錄 一、導讀二、概覽三、 使用3.1 hprof 文件準備3.1.1 Android sutdi…

【SpringBoot學習筆記】04. Thymeleaf模板引擎

模板引擎 所有的html元素都可以被thymeleaf替換接管 th:元素名 templates下的只能通過Controller來跳轉,templates前后端分離,需要模板引擎thymeleaf支持 模板引擎的作用就是我們來寫一個頁面模板,比如有些值呢,是動態的&#x…

cuda+anaconda+pytorch按照教程

首先安裝顯卡對應的CUDA版本,關鍵點在于區別顯卡支持的CUDA最高版本和運行版本 1、查看當前顯卡支持的最高版本,有兩種方式: 1)NVIDIA控制面板—>幫助—>系統信息—>組件—>NVCUDA.dll對應版本 請注意,12…

2023年國賽數學建模思路 - 案例:ID3-決策樹分類算法

文章目錄 0 賽題思路1 算法介紹2 FP樹表示法3 構建FP樹4 實現代碼 建模資料 0 賽題思路 (賽題出來以后第一時間在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 算法介紹 FP-Tree算法全稱是FrequentPattern Tree算法,就是頻繁模…

項目:基于UDP的TFTP文件傳輸

1)tftp協議概述 簡單文件傳輸協議,適用于在網絡上進行文件傳輸的一套標準協議,使用UDP傳輸特點: 是應用層協議 基于UDP協議實現 數據傳輸模式 octet:二進制模式(常用) mail:已經不再…

分布式 - 服務器Nginx:一小時入門系列之代理緩沖與緩存

官方文檔:https://nginx.org/en/docs/http/ngx_http_proxy_module.html 1. 代理緩沖 proxy_buffer 代理緩沖用于臨時存儲從后端服務器返回的響應數據。通過使用代理緩沖,Nginx可以在接收完整的響應后再將其發送給客戶端,從而提高性能和效率…

docker版jxTMS使用指南:使用jxTMS采集數據之三

本文是如何用jxTMS進行數據采集的第三部分,整個系列的文章請查看:docker版jxTMS使用指南:4.4版升級內容 docker版本的使用,請查看:docker版jxTMS使用指南 4.0版jxTMS的說明,請查看:4.0版升級內…

LeetCode 2682. 找出轉圈游戲輸家

【LetMeFly】2682.找出轉圈游戲輸家 力扣題目鏈接:https://leetcode.cn/problems/find-the-losers-of-the-circular-game/ n 個朋友在玩游戲。這些朋友坐成一個圈,按 順時針方向 從 1 到 n 編號。從第 i 個朋友的位置開始順時針移動 1 步會到達第 (i …

照耀國產的星火,再度上新!

國產之光,星火閃耀 ? 新時代的星火? 多模態能力? 圖像生成與虛擬人視頻生成? 音頻生成與OCR筆記收藏? 助手模式更新? 插件能力? 代碼能力? 寫在最后 ? 新時代的星火 在這個快速變革的時代,人工智能正迅猛地催生著前所未有的革命。從醫療到金融…

使用老北鼻AI免費GPT對話解決gun make安裝和解析iso9660的問題

在學習解析ISO9660鏡像文件時,使用了GPT來了解相關的庫和gun make編譯器的相關知識。這個過程可真是一言難盡,每個問題的回答都模棱兩可都需要去證實,不能直接復制粘貼,也不能說GPT的回答一點用也沒有,至少GPT給出了一…

自然語言處理從入門到應用——LangChain:記憶(Memory)-[聊天消息記錄]

分類目錄:《自然語言處理從入門到應用》總目錄 Cassandra聊天消息記錄 Cassandra是一種分布式數據庫,非常適合存儲大量數據,是存儲聊天消息歷史的良好選擇,因為它易于擴展,能夠處理大量寫入操作。 # List of contact…