温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java中的synchronized怎么用

发布时间:2022-04-14 10:53:49 来源:亿速云 阅读:180 作者:iii 栏目:开发技术

这篇“Java中的synchronized怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中的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());
    }

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

    Java中的synchronized怎么用cdn.nlark.com/yuque/0/2022/png/92791/1643426201331-a9d1c594-1ad6-4366-8384-28ff1ffaed01.png">

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

    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());
    }

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

    Java中的synchronized怎么用

    以上就是关于“Java中的synchronized怎么用”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI