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.mzph.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(…