synchronized使用

目錄

問題描述

1 鎖方法

2 鎖代碼塊

3 鎖某個類

4 靜態方法上的synchronized


當我們處理多線程處理同步問題的時候就會用到synchronized這個關鍵字,下面介紹下synchronized的四種用法。

問題描述

介紹之前我們先來看下,在java 多線程中 如果沒有線程同步會出現什么問題:

下面這個是一個測試例子:

public class MainClass {public static class MyRun implements Runnable{private int count=0;@Overridepublic void run() {while (count<15){System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;try {Thread.sleep(200);}catch (Exception e){}}}}public  static void main(String args[]){  MyRun myRun=new MyRun();Thread threadA=new Thread(myRun,"A");Thread threadB=new Thread(myRun,"B");threadA.start();threadB.start();}}

運行結果:

ThreadName:A? count:0

ThreadName:B? count:0

ThreadName:A? count:1

ThreadName:A? count:3

ThreadName:B? count:2

ThreadName:A? count:4

ThreadName:A? count:6

ThreadName:A? count:7

ThreadName:B? count:5

我們看到這個count在無序的增加,這個是由于A,B兩個線程同時操作Count變量造成的,如果我們想讓Count有序增加,應該給

System.out.print("ThreadName:"+Thread.currentThread().getName()+"? count:"+count+"\n");

??????????????????? count++;

這段代碼同步枷鎖,這樣當B線程進入這里時候,發現這里已經被鎖,就只有等待,A執行完這段代碼之后就會釋放對這個對象的這段代碼的釋放鎖,A獲得了釋放鎖,就可以進入執行,讓A,B有序進入執行,才能讓Count有序增加,加入了synchronized之后的代碼:

 while (count<15) {synchronized (this){System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;}try {Thread.sleep(200);}catch (Exception e){}}

結果:

ThreadName:A? count:0

ThreadName:B? count:1

ThreadName:B? count:2

ThreadName:A? count:3

ThreadName:A? count:4

ThreadName:B? count:5

ThreadName:B? count:6

ThreadName:A? count:7

ThreadName:B? count:8

加了鎖之后A,B線程就可以有序的交替執行,不會同時搶占執行Count++ 操作,

下面介紹synchronised的幾種用法。

1 鎖方法

public synchronized void dodo(){ }

這個就是鎖方法,這里面要注意兩點:

synchronized 關鍵子不是方法的一部分,所以它不會被繼承,說白了,就是如果父類的方法有synchronized,子類重寫這個方法,synchronized不寫也不會報錯

synchronized 不能修飾接口

synchronized 不能修復構造方法,但是可以修飾構造方法里面的代碼塊

2 鎖代碼塊

鎖代碼塊就是我上面的那個例子寫法了,這個就是鎖的是某個對象中的某個代碼,讓它線程同步。
?

 synchronized (this) {System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;}

我們看到這個synchronized (this) 里面的this,這里是要傳入一個對象的,如果不用this也可以,也可以在這個類里面new一個其他對象效果也是一樣的,比如


??

      private Object obj=new Object();@Overridepublic void run() {while (count<15){synchronized (obj){System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;}try {Thread.sleep(200);}catch (Exception e){}}}

這里就用了obj這個new的對象,效果和this完全一樣

3 鎖某個類

public class MainClass {public static class MyRun implements Runnable{public static int count=0;@Overridepublic void run() {while (count<15){synchronized (this){System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;}try {Thread.sleep(200);}catch (Exception e){}}}public synchronized void dodo(){}}public  static void main(String args[]){MyRun myRun1=new MyRun();MyRun myRun2=new MyRun();Thread threadA=new Thread(myRun1,"A");Thread threadB=new Thread(myRun2,"B");threadA.start();threadB.start();}}

這個代碼里面,

?MyRun myRun1=new MyRun();

?MyRun myRun2=new MyRun();

我new兩個MyRun,我前面說過synchronized(this)只能鎖某個對象,就是說threadA執行myRun1 threadB執行myRun2,互不干擾,synchronized只能鎖自己的run1 或者run2 不能兩個對象同時鎖到,所以執行的結果是無序的。

ThreadName:A? count:0

ThreadName:B? count:0

ThreadName:B? count:2

ThreadName:A? count:2

ThreadName:B? count:4

ThreadName:A? count:4

ThreadName:A? count:6

ThreadName:B? count:6

ThreadName:A? count:8

ThreadName:B? count:8

如果我們想讓兩個線程有序執行,這個Count++操作,而且對run1,和run2都同時鎖,應該怎么辦呢???

答案是鎖類,鎖類的意思是不管是這個類new了多少對象,這個對象的所有方法,都會上鎖,我們更改下代碼看看結果,怎么鎖類的:

?synchronized (MyRun.class) {

??????????????????????? System.out.print("ThreadName:"+Thread.currentThread().getName()+"? count:"+count+"\n");

??????????????????????? count++;

??????????????????? }

我們看到只改動了 synchronized (MyRun.class)這里,其他代碼都不變們,這個就把這個MyRun鎖了,我們看看結果:

ThreadName:A? count:0

ThreadName:B? count:1

ThreadName:B? count:2

ThreadName:A? count:3

ThreadName:B? count:4

ThreadName:A? count:5

ThreadName:A? count:6

ThreadName:B? count:7

ThreadName:A? count:8

結果是有序的,驗證了我們的結果

4 靜態方法上的synchronized

public synchronized? static void ddo()

這種方式其實和第三種效果是一樣的,都是對類起作用,因為我們知道static修飾的方法是類方法,所以這個synchronized 也是作用于整個類

我們把上面的代碼改下看看效果是不是一樣:

public class MainClass {public static class MyRun implements Runnable{public static int count=0;@Overridepublic void run() {ddo();}public synchronized  static void ddo(){while (count<15){System.out.print("ThreadName:"+Thread.currentThread().getName()+"  count:"+count+"\n");count++;try {Thread.sleep(200);}catch (Exception e){}}}}public  static void main(String args[]){MyRun myRun1=new MyRun();MyRun myRun2=new MyRun();Thread threadA=new Thread(myRun1,"A");Thread threadB=new Thread(myRun2,"B");threadA.start();threadB.start();}}

結果:

ThreadName:A? count:0

ThreadName:A? count:1

ThreadName:A? count:2

ThreadName:A? count:3

ThreadName:A? count:4

ThreadName:A? count:5

ThreadName:A? count:6

ThreadName:A? count:7

ThreadName:A? count:8

因為A線程 先執行最后滿足條件 while (count<15),所以B沒有機會執行了,驗證符合我們的預期

總結

1、鎖如果加在方法上面,或者在方法中的代碼塊形式,就是鎖的這個對象,如果鎖是靜態方法中,或者代碼塊synchronized(A.class) 形式 就是鎖的這個類,里面的所有方法都會同步。

2、誰擁有了鎖,上面線程就擁有了控制這段代碼的能力,其他的線程只能看著,只有釋放了鎖,其他線程才可以操作。

3、synchronized 消耗系統性能,所以能不加鎖的邏輯,盡量不要加。

4、操作讀寫文件,或者數據庫,有的時候多線程會出現不可預知的問題,所以要加入鎖。

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

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

相關文章

leetcode1. 兩數之和

題目&#xff1a;leetcode1. 兩數之和 描述&#xff1a; 給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數&#xff0c;并返回它們的數組下標。 你可以假設每種輸入只會對應一個答案。但是&#xff0c;數組中…

QT:UI控件(按設計師界面導航界面排序)

基礎部分 創建新項目&#xff1a;QWidget&#xff0c;QMainWindow&#xff0c;QDialog QMainWindow繼承自QWidget&#xff0c;多了菜單欄; QDialog繼承自QWidget&#xff0c;多了對話框 QMainWindow 菜單欄和工具欄&#xff1a; Bar: 菜單欄&#xff1a;QMenuBar&#xff0…

A Survey for In-context Learning

A Survey for In-context Learning 摘要&#xff1a; 隨著大語言模型(LLMs)能力的增長&#xff0c;上下文學習(ICL)已經成為一個NLP新的范式&#xff0c;因為LLMs僅基于幾個訓練樣本讓內容本身增強。現在已經成為一個新的趨勢去探索ICL來評價和extrapolate LLMs的能力。在這篇…

微服務06-分布式事務解決方案Seata

1、Seata 概述 Seata事務管理中有三個重要的角色: TC (Transaction Coordinator) - **事務協調者:**維護全局和分支事務的狀態,協調全局事務提交或回滾。 TM (Transaction Manager) - **事務管理器:**定義全局事務的范圍、開始全局事務、提交或回滾全局事務。 RM (Resourc…

Java地圖專題課 基本API BMapGLLib 地圖找房案例 MongoDB

本課程基于百度地圖技術&#xff0c;由基礎入門開始到應用實戰&#xff0c;適合零基礎入門學習。將企業項目中地圖相關常見應用場景的落地實戰&#xff0c;包括有地圖找房、輕騎小程序、金運物流等。同時講了基于Netty實現高性能的web服務&#xff0c;來處理高并發的問題。還講…

ttf-dejavu fontconfig字體

ttf-dejavu fontconfig是驗證碼&#xff0c;pdf&#xff0c;excel時需要用到的字體 編輯dockerfile&#xff0c;先切換國內鏡像源&#xff0c;默認alpinelinux是國外源&#xff0c;下載包會很慢 vim Dockerfile FROM alpine:latest RUN sed -i s/dl-cdn.alpinelinux.org/mirr…

【創建型設計模式】C#設計模式之原型模式

原型模式是一種創建型設計模式&#xff0c;它通過復制現有對象來創建新對象&#xff0c;而無需通過實例化的方式。它允許我們使用已經存在的對象作為藍本&#xff0c;從而創建新的對象&#xff0c;這樣可以避免重復初始化相似的對象&#xff0c;提高了對象的創建效率。 現在給…

Sentinel

1、熔斷降級限流 熔斷 A服務調用B服務的某個功能&#xff0c;由于網絡不穩定、B服務卡機等問題&#xff0c;導致功能時間超長。如果這樣子的次數太多&#xff0c;我們就可以直接將B斷路&#xff08;A不再請求B接口&#xff09;&#xff0c;凡是調用B服務的直接返回降級數據&a…

13-數據結構-串以及KMP算法,next數組

串 目錄 串 一、串&#xff1a; 二、串的存儲結構&#xff1a; 三、模式匹配 1.簡單模式匹配&#xff08;BF算法&#xff09; 2.KMP算法 2.1-next&#xff08;j&#xff09;數組手工求解 2.2-nextval&#xff08;j&#xff09;數組手工求解 一、串&#xff1a; 內容受…

JVM垃圾回收篇-垃圾回收算法

JVM垃圾回收篇-垃圾回收算法 標記清除&#xff08;Mark Sweep&#xff09; 概念 collector指的就是垃圾收集器。 mutator是指除了垃圾收集器之外的部分&#xff0c;比如說我們的應用程序本身。 mutator的職責一般是NEW(分配內存)、READ(從內存中讀取內容)、WRITE(將內容寫入內…

將多個單獨的 Excel 文件合并成一個,并添加標題行

要將多個單獨的 Excel 文件合并成一個&#xff0c;并添加標題行&#xff0c;可以使用 Python 的 pandas 庫。以下是一個示例代碼&#xff0c;假設要合并的 Excel 文件都在同一個文件夾中&#xff1a; import os import pandas as pd # 指定文件夾路徑 folder_path path/to/fo…

vscode搭建c語言環境問題

c語言環境搭建參考文章:【C語言初級階段學習1】使用vscode運行C語言&#xff0c;vscode配置環境超詳細過程&#xff08;包括安裝vscode和MinGW-W64安裝及后續配置使用的詳細過程&#xff0c;vscode用戶代碼片段的使用&#xff09;[考研專用]_QAQshift的博客-CSDN博客 問題如下:…

[C++ 網絡協議] 套接字和地址族、數據序列

目錄 1. 套接字 1.1 在Linux平臺下構建套接字 1.1.1 用于接聽的套接字(服務器端套接字) 1.1.2 用于發送請求的套接字(客戶端套接字) 1.2 在Windows平臺下構建套接字 1.2.1 Winsock的初始化 1.2.2 用于接聽的套接字(服務器端套接字) 1.2.3 用于發送請求的套接字(客戶端套…

pytest框架快速進階篇-pytest前置和pytest后置,skipif跳過用例

一、Pytest的前置和后置方法 1.Pytest可以集成unittest實現前置和后置 importunittestimportpytestclassTestCase(unittest.TestCase):defsetUp(self)->None:print(unittest每個用例前置)deftearDown(self)->None:print(unittest每個用例后置)classmethoddefsetUpClass…

jmeter中用戶參數和用戶定義的變量的區別

如果使用jmeter做過參數化的人都知道&#xff0c;參數化的方式有多種&#xff0c;其中一種就是使用用戶定義的變量&#xff0c;還有一種是使用用戶參數。那么&#xff0c;這兩個有什么異同呢&#xff1f; 一、先說相同的點&#xff1a; 1、都可以參數化&#xff0c;以供sample…

allure測試報告

使用pytest結合Allure進行測試報告生成的簡單教程 allure測試報告 Allure基于Java開發&#xff0c;因此我們需要提前安裝Java 8或以上版本的環境。 ◆安裝allure-pytest插件在DOS窗口輸入命令“pip3 install allure-pytest”&#xff0c;然后按“Enter”鍵。 下載安裝Allure…

使用 Docker 部署 canal 服務實現MySQL和ES實時同步

文章目錄 0. 環境介紹0. 前置步驟1. 安裝Kibana和Elasticsearch2. 安裝Canal和Canal Adapter2.1 修改數據庫配置2.1.1 修改配置2.1.2 驗證mysql binlog配置2.1.3 查看日志文件2.1.4 用JDBC代碼插入數據庫 2.2 安裝Canal Server2.3 安裝Canal Adapter修改兩處配置文件配置文件取…

Linux 命令篇

一、啟動網絡命令 ip addr 查看網卡信息 service network start 啟動網卡 service network stop 關閉網卡 service network restart 重啟網絡 二、pwd 命令 查看當前目錄的路徑 linux 下所有的絕對路徑都是從根目錄 "/" 開始 root:是linux下root用戶的根目…

初識mysql數據庫之引入mysql客戶端庫

目錄 一、下載第三方庫 1. 準備工作 1. 使用mysql官網提供的庫 2. yum源安裝 二、測試第三方庫是否可用 三、mysql常用接口介紹 1. 查看官方文檔 2. 初始化 3. 關閉mysql 4. 連接mysql 5. 下達sql指令 四、一個簡單的C客戶端庫連接mysql程序 1. 頭文件 2. 初始化…

FFmpeg接收UDP碼流

一、FFmpeg參數初始化&#xff1a; //在打開碼流前指定各種參數比如:探測時間/超時時間/最大延時等//設置緩存大小,1080p可將值調大av_dict_set(&options, "buffer_size", "8192000", 0);//以tcp方式打開,如果以udp方式打開將tcp替換為udpav_dict_set(…