在Java中,synchronized关键字提供了内置的支持来实现同步访问共享资源,以避免并发问题。synchronized主要有三种加锁方式:

1.同步实例方法

当一个实例方法被声明为synchronized时,该方法将同一时间只能被一个线程访问。锁是当前对象实例(即this)。

public class SynchronizedInstanceMethod {
public synchronized void doSomething() {
// 同步代码块
// 同一时间只能有一个线程执行这里的代码
} public static void main(String[] args) {
SynchronizedInstanceMethod obj = new SynchronizedInstanceMethod();
// 创建多个线程访问obj的doSomething方法,它们将串行执行
// ...
}
}

当我们创建了两个线程来并发地增加计数器,由于我们使用了synchronized,因此计数器的增加线程是安全的,即使两个线程都在尝试修改同一个共享变量。在同步实例方法中,锁分别是实例对象和类对象。

public class SynchronizedInstanceMethodExample {
private int count = 0; // 同步实例方法,锁定的是当前对象的实例(this)
public synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + " incremented count to " + count);
} public static void main(String[] args) {
final SynchronizedInstanceMethodExample example = new SynchronizedInstanceMethodExample(); // 创建两个线程来增加计数器
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
}, "Thread-1"); Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
}, "Thread-2"); // 启动线程
thread1.start();
thread2.start(); // 等待线程完成
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
} // 输出最终计数
System.out.println("Final count: " + example.count);
}
}

2.同步静态方法

当一个静态方法被声明为synchronized时,该方法将同一时间只能被一个线程访问。锁是Class对象,而不是实例对象。

public class SynchronizedStaticMethod {
public static synchronized void doSomethingStatic() {
// 同步代码块
// 同一时间只能有一个线程执行这里的代码
} public static void main(String[] args) {
// 创建多个线程访问SynchronizedStaticMethod的doSomethingStatic方法,它们将串行执行
// ...
}
}

当我们创建了两个线程来并发地增加计数器,由于我们使用了synchronized,因此计数器的增加线程是安全的,即使两个线程都在尝试修改同一个共享变量。在同步静态方法中,锁分别也是实例对象和类对象。

public class SynchronizedStaticMethodExample {
private static int count = 0; // 同步静态方法,锁定的是当前对象的类(Class)对象
public static synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + " incremented static count to " + count);
} public static void main(String[] args) {
// 创建两个线程来增加计数器
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
}, "Thread-1"); Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
}, "Thread-2"); // 启动线程...
// 等待线程完成...
// 输出最终计数...
// (与上面的例子类似,但省略了重复的代码)
}
}

3.同步代码块

我们可以使用synchronized关键字来定义一个代码块,而不是整个方法。在这种情况下,你可以指定要获取的锁对象。这提供了更细粒度的同步控制。

public class SynchronizedBlock {
private final Object lock = new Object(); // 用于同步的锁对象 public void doSomething() {
synchronized (lock) {
// 同步代码块
// 同一时间只有一个线程能够执行这里的代码
} // 这里的代码不受同步代码块的约束
} public static void main(String[] args) {
SynchronizedBlock obj = new SynchronizedBlock();
// 创建多个线程访问obj的doSomething方法,但只有在synchronized块中的代码将串行执行
// ...
}
}

在上面的SynchronizedBlock类中,我们创建了一个私有的Object实例lock作为锁对象。当线程进入synchronized (lock)块时,它会尝试获取lock对象的锁。如果锁已经被其他线程持有,那么该线程将被阻塞,直到锁被释放。

当我们创建了两个线程来并发地增加计数器,同步代码块的例子中,我们显式地指定了一个对象作为锁。

public class SynchronizedBlockExample {
private final Object lock = new Object(); // 用于同步的锁对象
private int count = 0; // 同步代码块,指定了锁对象
public void increment() {
synchronized (lock) {
count++;
System.out.println(Thread.currentThread().getName() + " incremented count to " + count);
}
} public static void main(String[] args) {
// 类似于上面的例子,但使用SynchronizedBlockExample的increment方法
// ...(省略了重复的代码)
}
}

注意:使用synchronized时应该尽量避免在持有锁的情况下执行耗时的操作,因为这会导致其他等待锁的线程长时间阻塞。同时,过度使用synchronized可能会导致性能下降,因为它会引入线程间的竞争和可能的上下文切换。在设计并发程序时,应该仔细考虑同步的粒度,并可能使用其他并发工具(如ReentrantLockSemaphoreCountDownLatch等)来提供更细粒度的控制。

java的synchronized有几种加锁方式的更多相关文章

  1. 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

    一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...

  2. 【转载】Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式…)介绍

    转载地址:http://blog.csdn.net/truong/article/details/46711045 关键字:Redis的Java客户端Jedis的八种调用方式(事务.管道.分布式…)介 ...

  3. Java多线程有哪几种实现方式? Java中的类如何保证线程安全? 请说明ThreadLocal的用法和适用场景

    java的同步机制,大概是通过:1.synchronized:2.Object方法中的wait,notify:3.ThreadLocal机制来实现的, 其中synchronized有两种用法:1.对类 ...

  4. JAVA中单例模式的几种实现方式

    1 线程不安全的实现方法 首先介绍java中最基本的单例模式实现方式,我们可以在一些初级的java书中看到.这种实现方法不是线程安全的,所以在项目实践中如果涉及到线程安全就不会使用这种方式.但是如果不 ...

  5. 使用java配置定时任务的几种配置方式及示例

    Spring定时器,主要有两种实现方式,包括Java Timer定时和Quartz定时器! 1.Java Timer定时 首先继承java.util.TimerTask类实现run方法 package ...

  6. Java中String对象两种赋值方式的区别

    本文修改于:https://www.zhihu.com/question/29884421/answer/113785601 前言:在java中,String有两种赋值方式,第一种是通过“字面量”赋值 ...

  7. 细说java中Map的两种迭代方式

    曾经对java中迭代方式总是迷迷糊糊的,今天总算弄懂了.特意的总结了一下.基本是算是理解透彻了. 1.再说Map之前先说下Iterator: Iterator主要用于遍历(即迭代訪问)Collecti ...

  8. Java中Map的4种遍历方式

    第一种方式:这是平常用的最多也最可取的一种遍历方式. for (Map.Entry<String, Object> entry : map.entrySet()) { System.out ...

  9. 基于Java的二叉树的三种遍历方式的递归与非递归实现

    二叉树的遍历方式包括前序遍历.中序遍历和后序遍历,其实现方式包括递归实现和非递归实现. 前序遍历:根节点 | 左子树 | 右子树 中序遍历:左子树 | 根节点 | 右子树 后序遍历:左子树 | 右子树 ...

  10. Java线程池的四种创建方式

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程. newFix ...

随机推荐

  1. 三七互娱《斗罗大陆:魂师对决》上线,Network Kit助力玩家即刻畅玩

    三七游戏旗下的年度旗舰大作<斗罗大陆:魂师对决>现已开启全平台公测.8月1日,三七互娱技术副总监出席了HMS Core.Sparkle游戏应用创新沙龙,展示了在HMS Core Netwo ...

  2. cmd中怎么清屏--cls

    平时我们在 Linux 系统中清除屏幕 用的命令是:  clear 现在在Windows上用的清屏命令是 : cls

  3. 第十三篇:HTML和CSS入门

    一.HTML本质以及在WEB程序中的作用 1.一套规则,浏览器认识的规则. 2.开发者: 学习html规则 开发后台程序 - 写html文件(充当模板的作用) - 数据库获取数据,然后替换到html文 ...

  4. k8s 深入篇———— k8s 的pod[五]

    前言 简单整理一下pod的相关知识. 正文 为什么我们需要pod. 前面我们知道了k8s一个最重要的作用是解决容器的编排功能,那么为什么有一个pod的东西. 这就是实际中遇到的问题. 那就是容器和容器 ...

  5. c# .net缓存(旧)

    前言 是迁移以前的blog. 关于c# 缓存在web应用中的一个引导,能够建立起一个缓存的基本思路. System.Web.Caching 这个真的是老生常谈了,我们只需要key和iv,然后我们就可以 ...

  6. 第五章-for循环的练习

    /* * @Issue: 每个苹果0.8元,第一天买两个苹果,从第二天开始,每天买前一天的两倍,直至购买的苹果数量 * 个数达到不超过100的最大值,编写程序求每天平均花多少钱. * @Author: ...

  7. eclipse 卡顿的优化办法

    1. 关闭校验 2. 关闭插件自动升级 3.关闭界面设置的一些选项

  8. Unity性能优化——托管堆/GC

    了解托管堆 许多 Unity 开发者面临的另一个常见问题是托管堆的意外扩展.在 Unity 中,托管堆的扩展比收缩容易得多.此外,Unity 的垃圾收集策略往往会使内存碎片化,因此可能阻止大型堆的收缩 ...

  9. vue使用 elementUI中el-upload的遇到的问题总结

    使用场景,使用el-upload上传文件,选择文件后不立即上传到服务器上,点击提交按钮时与其他form表单数据一起提交,类似的需求,相信有很多小伙伴遇到,可能也会遇到跟我一起的问题,在这里记录一下 & ...

  10. ElasticSearch 7.7 + Kibana的部署

    ElasticSearch目前最新版是7.7.0,其中部署的细节和之前的6.x有很多的不同,所以这里单独拉出来写一下,希望对用7.x的童鞋有一些帮助,然后部署完ES后配套的kibana也是7.7.0, ...