「并发编程」Synchronized的方法与同步块的区别

前言

一、块与方法

首先我们要明白什么是块、 什么是方法

代码块即java代码中用{ }括起来的代码段。

非静态代码块:

作用在方法当中,作用是控制变量的生命周期。

public class Test {
    {
        System.out.println("非静态代码块");//非静态代码块每次创建对象时都会执行
    }

    public static void main(String[] args) {
        new Test();
        new Test();
    }
}

静态代码块:

在类中的成员位置,{}前用static修饰,作用在于对类进行初始化。

public class Test {
    static {
        System.out.println("非静态代码块");//非静态代码块每次创建对象时都会执行
    }
 
    public static void main(String[] args) {
        new Test();
        new Test();
    }
}

方法

方法在很多地方被称为函数,方法是一段可以被重复执行的代码块。

方法用于定义类的某种行为或功能,其语法结构如下:

访问控制符 [修饰符] 返回值类型 方法名( [参数] )  {
           //方法体    
}

例如用于计算加法的方法

int add(int x, int y){
    return x + y;
}

本处只是简单介绍,具体......

进入正题

二、同步方法

由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法: synchronized方法synchronized块

//同步方法
public synchronized void method(int args){}

synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个 synchronized,方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞。方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

缺陷

若将一个大的方法申明为synchronized将会影响效率。如果方法有A代码(只读)和B代码(写、修改),使用同步方法锁住A代码会会影响效率。由此我们引入了同步块

三、同步块

synchronized(Obj){}//Obj为需要锁住的对象(会变化的量)

Obj

Obj称之为同步监视器

执行过程

同步监视器的执行过程

四、案例分析

线程同步问题大都使用synchronized解决,有同步代码块和同步方法的两种方式,主要记一下这两种的区别

package cn.frozenpenguin.test;
 
public class Test {
    public void main(String[] args) {
        new Thread(()->{
            System.out.println("showA..");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            synchronized (this) {
                System.out.println("showB..");
            }
        }).start();
        new Thread(()->{
            String s = "1";
            synchronized (s) {
                System.out.println("showC..");
            }
        }).start();
    }
}

运行结果如下:

这段代码的打印结果是,showA…..showC…..会很快打印出来,showB…..会隔一段时间才打印出来,那么showB为什么不能像showC那样很快被调用呢?

  在启动线程1调用方法A后,接着会让线程1休眠3秒钟,这时会调用方法C,注意到方法C这里用synchronized进行加锁,这里锁的对象是s这个字符串对象。但是方法B则不同,是用当前对象this进行加锁,注意到方法A直接在方法上加synchronized,这个加锁的对象是什么呢?显然,这两个方法用的是一把锁。

由这样的结果,我们就知道这样同步方法是用什么加锁的了,由于线程1在休眠,这时锁还没释放,导致线程2只有在3秒之后才能调用方法B,由此,可知两种加锁机制用的是同一个锁对象,即当前对象。   另外,同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好。

五、总结

往期好文推荐:

[玫瑰] [玫瑰]「Java并发编程」初识Volatile(概念与特性)

[玫瑰][玫瑰] 8千字+40张图:六问 Kafka 为啥那么牛!

[玫瑰][玫瑰] 阿里面试败北:5种微服务注册中心如何选型?这几个维度告诉你!

[玫瑰][玫瑰] Spring Security架构和核心类一览

展开阅读全文

页面更新:2024-03-02

标签:方法   都会   监视器   线程   静态   加锁   区别   机制   对象   玫瑰   代码

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top