首页 > 编程语言 >java的synchronized有几种加锁方式

java的synchronized有几种加锁方式

时间:2024-05-20 18:30:27浏览次数:36  
标签:count 加锁 java Thread synchronized void 线程 public

在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等)来提供更细粒度的控制。

标签:count,加锁,java,Thread,synchronized,void,线程,public
From: https://www.cnblogs.com/TS86/p/18202578

相关文章

  • Java手机号校验规则最新
    一、最新的Java手机号校验规则在Java中,进行手机号校验通常使用正则表达式(Regex)来匹配手机号的格式。以下是一个基于当前(截至2024年)中国手机号规则的校验方法:中国手机号通常以数字1开头,第二位在3、4、5、7、8、9中选择,后面跟着9位数字,总共11位。以下是一个使用正则表达式实现手机......
  • java实现按比重抽奖
    java实现按比重抽奖目录java实现按比重抽奖方案轮盘抽奖示例关键点BinarySearch(二分查找)方案对于按比重抽奖的更优方案,可以考虑以下几种方法:轮盘抽奖(RouletteWheelSelection)原理:想象一个旋转的轮盘,每个奖品占据轮盘上与其权重成比例的区域。随机选择一个点并让其“落下......
  • java应用CPU占用率过高排查
    1.背景服务器CPU使用率告警,紧急排查。2.排查思路2.1top查看各进程的CPU占用率top查到进程的pid2.2查看该进程的所有线程top-Hp<pid>发现大量的GCtaskthread#的cpu使用超过90%,定位到时频繁GC导致,可能是内存不足引起#jstat监控GC情况,其中:<vmid> 是Java虚拟机......
  • what's the advantages of using Map over Object in JavaScript?
    what'stheadvantagesofusingMapoverObjectinJavaScript?在JavaScript中使用Map相对于Object有什么优势?prosconsdemoshttps://leetcode.com/studyplan/30-days-of-javascript/(......
  • 解决yarn打包时出现“FATAL ERROR: Reached heap limit Allocation failed - JavaScri
    1、......
  • CentOS7安装Java
    1.查看是否有安装Javarpm-qa|grepjavarpm-qa|grepjdkrpm-qa|grepgcj如果之前有安装就卸载安装rpm-qa|grepjava|xargsrpm-e--nodeps2.下载安装包https://www.oracle.com/java/technologies/downloads/#java83.上传CentOS7服务器这里我们使用的......
  • Java常用的JSON序列化与反序列化工具实践
    JSON简介:JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,通常用于在不同系统之间传输数据。它基于JavaScript对象语法,但已成为一种独立于语言的格式。JSON数据以键值对的形式组织,易于阅读和编写。为什么要使用JSON?1.简单易用:JSON的语法简单,易于理解和编写,可以......
  • JavaScript------querySelector/querySelectorAll的使用
    1、基础语法querySelector()方法返回文档中匹配指定CSS选择器的一个元素。querySelector()方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用querySelectorAll()方法替代。属性:指定一个或多个匹配元素的CSS选择器。可以使用它们的id,类,类......
  • Java基础-转岗学习路线
    2023年初,因为公司项目的调整变化,原来的Unity项目取消了,没有其他适合的项目和岗位可以做了,公司也不进行裁员而是允许转岗,鉴于就业形势不佳以及我有机会来好好学习其他技术,于是我决定转岗Java后端开发,当然,总归还是迫于无奈,对我来说也是个不小的挑战,因为虽然做开发四年有余,有Java代码......
  • 【JAVA】BOSS系统发版艺术:构建高效、优雅的微服务部署策略
    在现代软件开发领域,微服务架构与容器化部署已迅速成为行业新趋势。微服务架构通过将应用拆分成多个小型、自治的服务单元,每个服务承担某项特定的业务功能。而容器化部署则以其轻量级和高度可移植的特性,为这些微服务的有效打包、分发和运行提供了强大支持。在这样的环境中,实现微服......