当前位置: 首页 > news >正文

java synchronized关键字介绍

Java 中的 synchronized 关键字用于实现线程安全,防止多个线程同时访问共享资源时出现数据不一致的问题。它可以用来修饰方法或者代码块,确保在同一时刻最多只有一个线程执行被 synchronized 修饰的代码。

使用场景

  1. 同步实例方法:确保同一实例的同步方法在同一时刻只能被一个线程访问。
  2. 同步静态方法:确保同一类的静态同步方法在同一时刻只能被一个线程访问。
  3. 同步代码块:提供更细粒度的控制,锁定指定对象。

1. 同步实例方法

使用 synchronized 修饰实例方法,表示整个方法是同步的,锁定当前实例 (this)。

public class Counter {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}
}

在上述例子中,increment 方法是同步的,意味着同一时刻最多只有一个线程可以执行它。

2. 同步静态方法

使用 synchronized 修饰静态方法,表示整个方法是同步的,锁定的是类对象 (Class),而不是实例对象。

public class Counter {private static int count = 0;public static synchronized void increment() {count++;}public static int getCount() {return count;}
}

在这个例子中,increment 静态方法是同步的,意味着同一时刻最多只有一个线程可以执行它。

3. 同步代码块

使用 synchronized 修饰代码块,可以锁定任意对象,实现更细粒度的同步控制。

public class Counter {private int count = 0;private final Object lock = new Object();public void increment() {synchronized (lock) {count++;}}public int getCount() {return count;}
}

在这个例子中,synchronized 代码块锁定了 lock 对象,只在需要同步的部分进行同步控制,而不是整个方法。

工作原理

Java 中的每个对象都有一个内部锁 (或监视器),当一个线程进入 synchronized 方法或代码块时,它会获取该对象的锁。当另一个线程试图进入相同对象的其他 synchronized 方法或代码块时,它必须等待直到第一个线程释放锁。

  • 对象锁:用于实例方法和实例代码块。
  • 类锁:用于静态方法和静态代码块。

注意事项

  1. 避免死锁:不当使用 synchronized 可能导致死锁。死锁发生在两个或多个线程互相等待对方持有的锁,从而都无法继续执行。
  2. 减少锁的粒度:尽量减少锁定的范围,只在必要的代码块上使用 synchronized,避免锁定整个方法,减少性能开销。
  3. 考虑使用其他并发工具:在某些情况下,java.util.concurrent 包提供的工具(如 ReentrantLockReadWriteLock 等)比 synchronized 更灵活和高效。

示例

下面是一个多线程计数器的示例,使用 synchronized 实现线程安全:

public class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println("Final count: " + counter.getCount());}
}

这个示例中,我们创建了两个线程,每个线程对计数器调用 1000 次 increment 方法。由于 increment 方法被 synchronized 修饰,它在同一时刻只能被一个线程访问,从而保证了计数器的线程安全性。最终输出的计数器值将是 2000

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Three 圆柱坐标(Cylindrical)和 视锥体(Frustum)
  • 聊一聊中小企业如何开展持续交付
  • 【C++修行之道】string类练习题
  • 用HttpURLConnection复现http响应码405
  • 【记录】LaTex|LaTex 代码片段 Listings 添加带圆圈数字标号的箭头(又名 LaTex Tikz 库画箭头的简要介绍)
  • 【深度学习基础】MacOS PyCharm连接远程服务器
  • 小白学webgl合集-Three.js加载器
  • nginx的重定向
  • 【Windows】实现窗口子类化(基于远程线程注入)
  • QImage显示图片像素
  • 技术文件国产化准备
  • [C++] 轻熟类和对象
  • 内网信息收集:手动、脚本和工具查IP、端口
  • 5-3.损失函数
  • Docker 日志丢失 - 解决方案
  • 自己简单写的 事件订阅机制
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • emacs初体验
  • HTTP请求重发
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • JS实现简单的MVC模式开发小游戏
  • Linux链接文件
  • PaddlePaddle-GitHub的正确打开姿势
  • Promise初体验
  • SpiderData 2019年2月16日 DApp数据排行榜
  • 构建工具 - 收藏集 - 掘金
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 开源地图数据可视化库——mapnik
  • 聊聊flink的BlobWriter
  • 目录与文件属性:编写ls
  • 如何实现 font-size 的响应式
  • 我这样减少了26.5M Java内存!
  • 正则学习笔记
  • 最简单的无缝轮播
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​iOS实时查看App运行日志
  • ​第20课 在Android Native开发中加入新的C++类
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #mysql 8.0 踩坑日记
  • (1)svelte 教程:hello world
  • (4)(4.6) Triducer
  • (接口封装)
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (学习总结16)C++模版2
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET Core引入性能分析引导优化
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .NetCore+vue3上传图片 Multipart body length limit 16384 exceeded.
  • .sys文件乱码_python vscode输出乱码
  • @JsonFormat 和 @DateTimeFormat 的区别