Java中synchronized用法汇总

目录
  • 用法简介
    • 1、修饰普通方法
    • 2、修饰静态方法
    • 3、修饰代码块
  • 总结

在 Java 语言中,保证线程安全性的主要手段是加锁,而 Java 中的锁主要有两种:synchronized 和 Lock,我们今天重点来看一下 synchronized 的几种用法。

用法简介

使用 synchronized 无需手动执行加锁和释放锁的操作,我们只需要声明 synchronized 关键字就可以了,JVM 层面会帮我们自动的进行加锁和释放锁的操作。
synchronized 可用于修饰普通方法、静态方法和代码块,接下来我们分别来看。

1、修饰普通方法

synchronized 修饰普通方法的用法如下:

/**
 * synchronized 修饰普通方法
 */
public synchronized void method() {
    // ....
}

当 synchronized 修饰普通方法时,被修饰的方法被称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。

2、修饰静态方法

synchronized 修饰静态方法和修饰普通方法类似,它的用法如下:

/**
 * synchronized 修饰静态方法
 */
public static synchronized void staticMethod() {
    // .......
}

当 synchronized 修饰静态方法时,其作用范围是整个程序,这个锁对于所有调用这个锁的对象都是互斥的。

所谓的互斥,指的是同一时间只能有一个线程能使用,其他线程只能排队等待。

修饰普通方法 VS 修饰静态方法

synchronized 修饰普通方法和静态方法看似相同,但二者完全不同,对于静态方法来说 synchronized 加锁是全局的,也就是整个程序运行期间,所有调用这个静态方法的对象都是互斥的,而普通方法是针对对象级别的,不同的对象对应着不同的锁,比如以下代码,同样是调用两次方法,但锁的获取完全不同,实现代码如下:

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SynchronizedUsage {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程池同时执行任务
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        // 执行两次静态方法
        threadPool.execute(() -> {
            staticMethod();
        });

        // 执行两次普通方法
            SynchronizedUsage usage = new SynchronizedUsage();
            usage.method();
            SynchronizedUsage usage2 = new SynchronizedUsage();
            usage2.method();
    }

    /**
     * synchronized 修饰普通方法
     * 本方法的执行需要 3s(因为有 3s 的休眠时间)
     */
    public synchronized void method() {
        System.out.println("普通方法执行时间:" + LocalDateTime.now());
        try {
            // 休眠 3s
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

     * synchronized 修饰静态方法
    public static synchronized void staticMethod() {
        System.out.println("静态方法执行时间:" + LocalDateTime.now());
}

以上程序的执行结果如下:

从上述结果可以看出,静态方法加锁是全局的,针对的是所有调用者;而普通方法加锁是对象级别的,不同的对象拥有的锁也不同。

3、修饰代码块

我们在日常开发中,最常用的是给代码块加锁,而不是给方法加锁,因为给方法加锁,相当于给整个方法全部加锁,这样的话锁的粒度就太大了,程序的执行性能就会受到影响,所以通常情况下,我们会使用 synchronized 给代码块加锁,它的实现语法如下:

public void classMethod() throws InterruptedException {
    // 前置代码...

    // 加锁代码
    synchronized (SynchronizedUsage.class) {
        // ......
    }

    // 后置代码...
}

从上述代码我们可以看出,相比于修饰方法,修饰代码块需要自己手动指定加锁对象,加锁的对象通常使用 this 或 xxx.class 这样的形式来表示,比如以下代码:

// 加锁某个类
synchronized (SynchronizedUsage.class) {
    // ......
}

// 加锁当前类对象
synchronized (this) {
    // ......
}

this VS class

使用 synchronized 加锁 this 和 xxx.class 是完全不同的,当加锁 this 时,表示用当前的对象进行加锁,每个对象都对应了一把锁;而当使用 xxx.class 加锁时,表示使用某个类(而非类实例)来加锁,它是应用程序级别的,是全局生效的,如以下代码所示:

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SynchronizedUsageBlock {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程池同时执行任务
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        // 执行两次 synchronized(this)
        threadPool.execute(() -> {
            SynchronizedUsageBlock usage = new SynchronizedUsageBlock();
            usage.thisMethod();
        });
            SynchronizedUsageBlock usage2 = new SynchronizedUsageBlock();
            usage2.thisMethod();

        // 执行两次 synchronized(xxx.class)
            SynchronizedUsageBlock usage3 = new SynchronizedUsageBlock();
            usage3.classMethod();
            SynchronizedUsageBlock usage4 = new SynchronizedUsageBlock();
            usage4.classMethod();
    }

    /**
     * synchronized(this) 加锁
     * 本方法的执行需要 3s(因为有 3s 的休眠时间)
     */
    public void thisMethod() {
        synchronized (this) {
            System.out.println("synchronized(this) 加锁:" + LocalDateTime.now());
            try {
                // 休眠 3s
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

     * synchronized(xxx.class) 加锁
    public void classMethod() {
        synchronized (SynchronizedUsageBlock.class) {
            System.out.println("synchronized(xxx.class) 加锁:" + LocalDateTime.now());
}

以上程序的执行结果如下:

总结

synchronized 用 3 种用法,用它可以来修饰普通方法、静态方法和代码块,其中最常用的是修饰代码块,而修饰代码块时需要指定一个加锁对象,这个加锁对象通常使用 this 或 xxx.class 来表示,当使用 this 时,表示使用当前对象来加锁,而使用 class 时,表示表示使用某个类(非类对象实例)来加锁,它是全局生效的。

到此这篇关于Java中synchronized用法汇总的文章就介绍到这了,更多相关java synchronized用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中Synchronized的用法解析

    简单介绍 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象: 3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象: 4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对

  • Java开发中synchronized的定义及用法详解

    概念 是利用锁的机制来实现同步的. 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问.互斥性我们也往往称为操作的原子性. 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致. 用法 修饰静态方法: //同步静态方法 public synchronized

  • java synchronized的用法及原理详解

    目录 为什么要用synchronized 使用方式 字节码语义 对象锁(monitor) 锁升级过程 为什么要用synchronized 相信大家对于这个问题一定都有自己的答案,这里我还是要啰嗦一下,我们来看下面这段车站售票的代码: /** * 车站开两个窗口同时售票 */ public class TicketDemo { public static void main(String[] args) { TrainStation station = new TrainStation(); //

  • Java中synchronized用法汇总

    目录 用法简介 1.修饰普通方法 2.修饰静态方法 3.修饰代码块 总结 在 Java 语言中,保证线程安全性的主要手段是加锁,而 Java 中的锁主要有两种:synchronized 和 Lock,我们今天重点来看一下 synchronized 的几种用法. 用法简介 使用 synchronized 无需手动执行加锁和释放锁的操作,我们只需要声明 synchronized 关键字就可以了,JVM 层面会帮我们自动的进行加锁和释放锁的操作.synchronized 可用于修饰普通方法.静态方法和

  • Java中线程用法总结

    本文实例总结了Java中线程用法.分享给大家供大家参考.具体分析如下: 1.线程是基本调度单元.共享进程的资源,如内存和文件句柄.但有自己的pc(程序计数器),stack(线程栈)及本地变量 2.线程的优势: a) 充分利用多处理器 b) 可以简化模型.特定任务给特定线程.如servlets及rmi等框架. c) 对异步事件的简单处理.如socket,nio使用更复杂.而现在的操作系统支持更大数量的线程. d) 界面的更佳响应 3.内部锁:synchronized块.互斥.可重入(reentra

  • Java中synchronized关键字引出的多种锁 问题

    前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这些锁分别的优缺点. 一 synchronized机制 synchronized关键字是JAVA中常用的同步功能,提供了简单易用的锁功能. synchronized有三种用法,分别为: 用在普通方法上,能够锁住当前对象.用在静态方法上,能够锁住类用在代码块上,锁住的是synchronized()里的对

  • Java中抽象类用法与注意点实例详解

    本文实例讲述了Java中抽象类用法与注意点.分享给大家供大家参考,具体如下: 一 抽象类的用法案例 1 代码 abstract class Person //定义一抽象类Person { String name; int age; String occupation; public abstract String talk(); // 声明一抽象方法talk() } class Student extends Person // Student类继承自Person类 { public Stude

  • 透彻理解Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别

    本文讲述了Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别.分享给大家供大家参考,具体如下: Synchronized和Static Synchronized区别 通过分析这两个用法的分析,我们可以理解java中锁的概念.一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全局锁(该锁针对的是类,无论实例多少个对象,那么线程都共享该锁).实例锁对应的就是synchronized关键字,而类锁(全局锁)对应的就是

  • Java中synchronized的几种使用方法

    目录 用法简介 1.修饰普通方法 2.修饰静态方法 修饰普通方法 VS 修饰静态方法 3.修饰代码块 this VS class 总结 前言: 在 Java 语言中,保证线程安全性的主要手段是加锁,而 Java 中的锁主要有两种:synchronized 和 Lock,我们今天重点来看一下 synchronized 的几种用法. 用法简介 使用 synchronized 无需手动执行加锁和释放锁的操作,我们只需要声明 synchronized 关键字就可以了,JVM 层面会帮我们自动的进行加锁和

  • 深入了解Java中Synchronized的各种使用方法

    目录 Synchronized关键字 Synchronized修饰实例方法 Synchronized修饰静态方法 Sychronized修饰多个方法 Synchronized修饰实例方法代码块 Synchronized修饰静态代码块 应该用什么对象作为锁对象 Synchronized与可见性和重排序 可见性 重排序 总结 在Java当中synchronized通常是用来标记一个方法或者代码块.在Java当中被synchronized标记的代码或者方法在同一个时刻只能够有一个线程执行被synchr

  • Java 中This用法的实例详解

     Java 中This用法的实例详解 用类名定义一个变量的时候,定义的只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法. 那们类里面是够也应该有一个引用来访问自己的属性和方法纳? 呵呵,Java提供了一个很好的东西,就是 this 对象,它可以在类里面来引用这个类的属性和方法.先来个简单的例子: public class ThisDemo { String name="Mick"; public void print(String name){ System.out.pr

  • java中synchronized(同步代码块和同步方法)详解及区别

     java中synchronized(同步代码块和同步方法)详解及区别 问题的由来: 看到这样一个面试题: //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized (obj){} } synchronized用于解决同步问题,当有多条线程同时访问共享数据时,如果进行同步,就会发生错误,Java提供的解决方案是:只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他

随机推荐