jajajajajajajava

線程

1 線程概念

進程:進程指正在內存中運行的程序。進程具有一定的獨立性。

線程:線程是進程中的一個執行單元。負責當前進程中程序的執行。一個進程中至少有一個線程。如果一個進程中有多個線程,稱之為多線程程序。

java中的線程采用的是搶占式調度,如果線程的優先級相同,那么會隨機選擇一個線程執行。理論上,優先級高的線程搶到CPU的概率更大。

CPU使用搶占式調度在多個線程間進行著高速的切換。對于CPU的一個核而言,某個時刻,只能執行一個線程。CPU在多個線程間切換的速度相對我們的感受要快得多,看上去就是在同時執行。

多線程程序并不能提高程序的運行速度,但是能夠提高程序的運行效率,讓CPU的使用率更高。

為什么要使用多線程?

  • 提高用戶體驗

  • 提高CPU的利用率

    • 線程在執行的過程中會和計算機硬件進行交互,線程和硬件交互的時候會暫時空置CPU,從而多線程可以提高CPU利用率

2 線程的創建

2.1 線程的創建方式一

  • 定義一個類繼承Thread

  • 重寫run方法

  • 創建子類對象

  • 調用start方法,開啟線程并讓線程執行

public class MyThread extends Thread{
?@Overridepublic void run() {// 把希望其他線程執行的代碼放在run方法中for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "正在執行了。。。");}}
}

2.2 線程的創建方式二[推薦]

  • 定義類實現Runnable接口

  • 實現接口中的run方法

  • 創建Thread類的對象

  • 將Runnable接口的實現類對象作為參數傳遞給Thread類的構造方法

  • 調用Thread類的start方法開啟線程

public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "正在執行");}}
}
?
?
public static void main(String[] args) {
// ? ? ?  MyRunnable myRunnable = new MyRunnable();
// ? ? ?  Thread thread = new Thread(myRunnable,"子線程");
// ? ? ?  thread.start();// 匿名內部類
// ? ? ?  new Thread(new Runnable() {
// ? ? ? ? ?  @Override
// ? ? ? ? ?  public void run() {
// ? ? ? ? ? ? ?  for (int i = 0; i < 100; i++) {
// ? ? ? ? ? ? ? ? ?  System.out.println(Thread.currentThread().getName() + "執行了");
// ? ? ? ? ? ? ?  }
// ? ? ? ? ?  }
// ? ? ?  }).start();// lambda表達式new Thread(()-> {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "執行了");}},"小線程").start();
?for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName());}}

課堂練習:售票案例:模擬電影院賣票,實現3個窗口同時賣"哪吒2"的100張票。

方式一:

public class Ticket implements Runnable{int ticket = 100;@Overridepublic void run() {while (true){if (ticket <= 0) {break;}
?System.out.println(Thread.currentThread().getName() + "您的票是" + ticket--);}}
}
?
?
public static void main(String[] args) {Ticket ticket = new Ticket();// 創建線程Thread thread1 = new Thread(ticket,"窗口1");Thread thread2 = new Thread(ticket,"窗口2");Thread thread3 = new Thread(ticket,"窗口3");thread1.start();thread2.start();thread3.start();}

方式二:

public class TicketDemo {
?static int ticket = 100;
?public static void saleTicket(){while (true){if (ticket <= 0) {break;}System.out.println(Thread.currentThread().getName() + "您的票是" + ticket--);}}
}
?
?
?public static void main(String[] args) {
// ? ? ?  new Thread(()->{
// ? ? ? ? ?  TicketDemo.saleTicket();
// ? ? ?  },"窗口1").start();new Thread(TicketDemo::saleTicket,"窗口1").start();new Thread(TicketDemo::saleTicket,"窗口2").start();new Thread(TicketDemo::saleTicket,"窗口3").start();}

經過多次運行會發現以上的內容可能會出現以下結果:

  • 有重復的票

  • 有0的票

  • 有-1的票

線程安全隱患:如果有多個線程在同時運行,而這些線程可能會同時運行某段代碼。程序每次運行的結果和單線程運行的結果一樣,而且其他的變量值也和預期的一樣,就是線程安全。否則就是有線程安全隱患。

線程安全隱患出現的條件:

  • 多線程

  • 有共享資源

  • 有修改操作

以上三個條件破壞一個就可以避免線程安全隱患

3 線程安全隱患解決方案

3.1 同步代碼塊

synchronized(鎖對象){可能會產生線程安全問題的代碼;
}

在同一個時刻,同步代碼塊中只能有一個線程執行,執行完畢之后會釋放鎖,所有線程再去搶鎖對象,搶到之后的線程可以執行同步代碼塊中的代碼,其他線程等待同步代碼塊執行完畢后釋放鎖。

同步代碼塊中的鎖對象可以是任意的對象,但是多個線程時,要使用同一個鎖對象才能夠保證線程安全。

3.2 同步方法

在方法上添加synchronized

public synchronized 返回值類型 ?方法名(參數){}

在同一個時刻,同步方法中只能有一個線程執行,執行完畢之后會釋放鎖,所有線程再去搶鎖對象,搶到之后的線程可以執行同步方法中的代碼,其他線程等待同步方法執行完畢后釋放鎖。

// 靜態同步方法// 鎖對象是  類名.classprivate synchronized void method2(){}
?// 同步方法 // 鎖對象是thisprivate synchronized boolean method() {if (ticket <= 0) {return true;}
?System.out.println(Thread.currentThread().getName() + "您的票是" + ticket--);return false;}

3.3 Lock

// 創建鎖Lock lock = new ReentrantLock();
?@Overridepublic void run() {while (true) {// 線程休眠  單位:毫秒try {Thread.sleep(1L);} catch (InterruptedException e) {throw new RuntimeException(e);}// 加鎖lock.lock();try {if (ticket <= 0) {break;}System.out.println(Thread.currentThread().getName() + "您的票是" + ticket--);} finally {// 釋放鎖lock.unlock();}
?}}

同步:一段代碼只允許一個線程執行

異步:一段代碼允許多個線程執行

同步一定是線程安全的

線程安全不一定同步

異步不一定線程不安全

線程不安全一定是異步

3.4 ThreadLocal

  • 從程序上游向下游傳遞數據

static    ThreadLocal<String> threadLocal = new ThreadLocal<>();public static void main(String[] args) {String str = "你好";threadLocal.set(str);a();}public static void a(){b();}private static void b() {c();}private static void c() {d();}private static void d() {String s = threadLocal.get();System.out.println(s);}

  • 可以解決線程安全隱患

public static ThreadLocal<Printer> tl = new ThreadLocal<>() {// 匿名內部類// 重寫初始化方法,返回一個打印機@Overrideprotected Printer initialValue() {return new Printer();}};public static void main(String[] args) {new Thread(new GFS()).start();new Thread(new BFM()).start();}}class Printer {public void print(String str) {System.out.println("打印機在打印" + str);}
}class BFM implements Runnable {@Overridepublic void run() {Printer printer = TestDemo4.tl.get();printer.print(printer + "我是白富美");printer.print(printer + "我很美");printer.print(printer + "很有錢");}
}class GFS implements Runnable {@Overridepublic void run() {Printer printer = TestDemo4.tl.get();printer.print(printer + "我是高富帥");printer.print(printer + "我很高");printer.print(printer + "也很帥");}
}

4 死鎖

死鎖:由于鎖的嵌套導致鎖之間相互鎖死的現象

public class TestDemo5 {static Print p = new Print();static Scan s = new Scan();public static void main(String[] args) {new Thread(()->{synchronized (p){p.print();try {Thread.sleep(1000L);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (s){s.scan();}}}).start();new Thread(()->{synchronized (s){s.scan();synchronized (p){p.print();}}}).start();}
}class Print{public void print(){System.out.println("打印機在打印");}
}class Scan{public void scan(){System.out.println("掃描儀在掃描");}
}

5 等待喚醒機制

package cn.javasm.demo;public class TestDemo6 {public static void main(String[] args) {Student student = new Student();new Thread(new Ask(student)).start();new Thread(new Change(student)).start();}
}class Change implements Runnable{private Student student;public Change(Student student) {this.student = student;}@Overridepublic void run() {while (true){synchronized (student){if (student.flag){try {// 讓當前線程陷入等待student.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}if ("周杰倫".equals(student.getName())){student.setName("林志玲");student.setGender("女生");}else {student.setName("周杰倫");student.setGender("男生");}student.flag = true;// 隨機喚醒一個正在等待的線程student.notify();}}}
}class Ask implements Runnable{private Student student;public Ask(Student student) {this.student = student;}@Overridepublic void run() {while (true){synchronized (student) {if (!student.flag){try {// 讓當前線程陷入等待student.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("老師,我是" + student.getName() + ",我是" + student.getGender() + ",我要問問題");student.flag = false;// 喚醒一個線程student.notify();}}}
}class Student{private String name;private String gender;// true讓Ask執行// false讓Change執行public boolean flag;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}
}

作業:完成生產者消費者模式

一個線程作為消費者,一個線程作為生產者。生產者每生產一次,消費者就消費一次。生產者每次生產的商品數量以及消費者消費的數量使用隨機數產生即可。每一次的生產的商品數量和上一次剩余的商品數量之和不能超過1000。

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

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

相關文章

虛擬機CentOS里JDK的安裝與環境配置

---本文以JDK17為例---步驟 1&#xff1a;進入/tmp臨時目錄# 進入臨時目錄 cd /tmp步驟 2&#xff1a;下載 Java 17 安裝包wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz步驟 3&am…

mybatis-plus多租戶兼容多字段租戶標識

默認租戶插件處理器的缺陷 在springboot工程中引入mybatis-plus的租戶插件TenantLineInnerInterceptor&#xff0c;能簡化我們的數據隔離操作&#xff0c;例如各類含租戶用戶登錄權限的rest接口中&#xff0c;不需要再根據登錄用戶-set租戶條件-觸發查詢&#xff0c;租戶插件能…

HBase高級特性(布隆過濾器和協處理器)、列族設計、rowkey設計以及熱點問題處理

在闡述HBase高級特性和熱點問題處理前&#xff0c;首先回顧一下HBase的特點&#xff1a;分布式、列存儲、支持實時讀寫、存儲的數據類型都是字節數組byte[]&#xff0c;主要用來處理結構化和半結構化數據&#xff0c;底層數據存儲基于hdfs。 同時&#xff0c;HBase和傳統數據庫…

redis sentinel 與 clauster 的區別

Redis Sentinel(哨兵)和Redis Cluster(集群)是Redis提供的兩種不同的高可用和擴展性解決方案,它們的設計目標和適用場景有顯著區別: 1. 核心功能與目標 Redis Sentinel 主要解決主從架構的高可用問題,實現自動故障轉移 監控主從節點狀態,當主節點故障時自動將從節點提…

MySQL數據庫中快速導入大數據sql

1.PwerShell命令頁面導入全表數據庫 -P3310 指定數據庫端口號Get-Content "本地sql文件目錄" | .\mysql -u root -p -P 33102.PwerShell命令頁面導入單表到數據庫 -P3310 指定數據庫端口號Get-Content "本地sql文件目錄" | .\mysql -u root -p -P 3310 數…

消息類型proto的編寫和生成

消息類型proto的編寫和生成 代碼如下&#xff1a; syntax"proto3"; package xypmq;enum ExchangeType {UNKNOWNTYPE0;DIRECT1;FANOUT2;TOPIC3; };enum DeliveryMode {UNKNOWNMODE0;UNDURABLE1;DURABLE2; };message BasicProperties {string id1;DeliveryMode deliver…

Vuetify:構建優雅Vue應用的Material Design組件庫

Vuetify是一個基于Material Design設計規范的Vue.js UI組件庫&#xff0c;它提供了80多個精心設計的組件&#xff0c;幫助開發者快速構建美觀且功能豐富的企業級應用。核心特性1. 完整的Material Design實現// 所有組件遵循Material Design規范 <v-btn color"primary&q…

SpringBoot 注解深剖:@RequestParam 與 @RequestBody 的終極對決,90% 的開發者都踩過這些坑!

在 SpringBoot 開發中&#xff0c;處理 HTTP 請求參數是我們每天都要面對的工作。而RequestParam和RequestBody這兩個注解&#xff0c;就像是我們手中的兩把利劍&#xff0c;既能高效解決問題&#xff0c;用不好也可能 "誤傷" 自己。作為一名資深 Java 開發者&#x…

【Docker】P2 Docker環境構建準備:MacOS 與 Linux

目錄操作系統與 Docker 的兼容性分析Docker 技術本質MacOS 環境下的 Docker 構建1. 安裝前準備2. Docker Desktop安裝3. 鏡像加速配置高級操作&#xff1a;文件共享配置Linux 環境下的 Docker 構建卸載歷史版本配置軟件源Docker 核心組件安裝系統服務配置鏡像加速器配置應用配置…

OpenCV 發票識別全流程:透視變換與輪廓檢測詳解

目錄 前言 一、核心技術原理&#xff1a;透視變換與輪廓檢測 1. 透視變換&#xff1a;讓傾斜發票 “正過來” &#xff08;1&#xff09;什么是透視變換&#xff1f; &#xff08;2&#xff09;透視變換的 5 個關鍵步驟 2. 輪廓檢測&#xff1a;精準定位發票區域 &#x…

并發:使用volatile和不可變性實現線程安全

《Java并發編程實戰》中的VolatileCachedFactorizer展示了如何使用volatile和不可變性來實現線程安全。解決了簡單緩存實現中可能出現的線程安全問題&#xff0c;同時避免了全量同步帶來的性能開銷。 場景背景 假設有一個服務&#xff08;如因數分解服務&#xff09;&#xff0…

Linux x86 stability和coredump

1 POSIX pthread_create原理 1&#xff09;fork()、pthread_create()、vfork()對應的系統調用分別是sys_fork()、sys_clone()、sys_vfork()&#xff0c;它們在內核中都是通過do_fork()實現的。 2&#xff09;系統中所有的進程都組織在init_task.tasks鏈表下面&#xff0c;每個進…

【PyTorch】多對象分割

對象分割任務的目標是找到圖像中目標對象的邊界。實際應用例如自動駕駛汽車和醫學成像分析。這里將使用PyTorch開發一個深度學習模型來完成多對象分割任務。多對象分割的主要目標是自動勾勒出圖像中多個目標對象的邊界。 對象的邊界通常由與圖像大小相同的分割掩碼定義&#xf…

RabbitMQ---面試題

總結我們所學內容&#xff0c;這里推薦博客進行復習 RabbitMQ---面試題_rabbitmq常問面試題-CSDN博客

MasterGo自動布局(Auto Layout)

自動布局是用來表示 子元素與子元素之間互相影響的一種排版方式,是一種響應式布局技術。一般是將所有元素設計完成后再使用自動布局進行設置。 自動布局就是響應式布局,就是在不同尺寸的手機上寬度不同都應該怎么展示。 一般頁面的一級元素使用約束進行相對定位,二級元素及里…

還在重啟應用改 Topic?Spring Boot 動態 Kafka 消費的“終極形態”

場景描述&#xff1a; 你的一個微服務正在穩定地消費 Kafka 的 order_topic。現在&#xff0c;上游系統為了做業務隔離&#xff0c;新增加了一個 order_topic_vip&#xff0c;并開始向其中投遞 VIP 用戶的訂單。你需要在不重啟、不發布新版本的情況下&#xff0c;讓你現有的消費…

使用vllm部署neo4j的text2cypher-gemma-2-9b-it-finetuned-2024v1模型

使用vllm部署neo4j的text2cypher-gemma-2-9b-it-finetuned-2024v1模型 系統環境準備 由于使用的基于 nvcr.io/nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 的 workbench,需要進行以下準備(其他系統環境可忽略) ldconfig -p | grep libcudnn 找到 libcudnn 的so庫,然…

Coze源碼分析-資源庫-創建知識庫-前端源碼-核心組件

概述 本文深入分析Coze Studio中用戶創建知識庫功能的前端實現。該功能允許用戶在資源庫中創建、編輯和管理知識庫資源&#xff0c;為開發者提供了強大的知識管理和數據處理能力。通過對源碼的詳細解析&#xff0c;我們將了解從資源庫入口到知識庫配置彈窗的完整架構設計、組件…

基于時空數據的網約車訂單需求預測與調度優化

一、引言隨著共享出行行業的蓬勃發展&#xff0c;網約車已成為城市交通的重要組成部分。如何精準預測訂單需求并優化車輛調度&#xff0c;是提升平臺運營效率、改善用戶體驗的關鍵。本文提出一種基于時空數據的網約車訂單需求預測與調度優化方案&#xff0c;通過網格化城市空間…

數據結構 Java對象的比較

在Java中&#xff0c;凡是涉及到比較的&#xff0c;可以分為兩類情況&#xff1a;一類是基本數據類型的比較&#xff0c;另一類是引用數據類型的比較。對于基本數據類型的比較&#xff0c;我們通過關系運算符&#xff08;、>、<、!、>、<&#xff09;進行它們之間的…