使用synchronized修饰静态方法和非静态方法有什么区别

欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

1、Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。

Java中每个对象都有一个锁,并且是唯一的。假设分配的一个对象空间,里面有多个方法,相当于空间里面有多个小房间,如果我们把所有的小房间都加锁,因为这个对象只有一把钥匙,因此同一时间只能有一个人打开一个小房间,然后用完了还回去,再由JVM 去分配下一个获得钥匙的人。


情况1:同一个对象在两个线程中分别访问该对象的两个同步方法

结果:会产生互斥。

解释:因为锁针对的是对象,当对象调用一个synchronized方法时,其他同步方法需要等待其执行结束并释放锁后才能执行。


情况2:不同对象在两个线程中调用同一个同步方法

结果:不会产生互斥。

解释:因为是两个对象,锁针对的是对象,并不是方法,所以可以并发执行,不会互斥。形象的来说就是因为我们每个线程在调用方法的时候都是new 一个对象,那么就会出现两个空间,两把钥匙,

2、Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。

情况1:用类直接在两个线程中调用两个不同的同步方法

结果:会产生互斥。

解释:因为对静态对象加锁实际上对类(.class)加锁,类对象只有一个,可以理解为任何时候都只有一个空间,里面有N个房间,一把锁,因此房间(同步方法)之间一定是互斥的。

:上述情况和用单例模式声明一个对象来调用非静态方法的情况是一样的,因为永远就只有这一个对象。所以访问同步方法之间一定是互斥的。


情况2:用一个类的静态对象在两个线程中调用静态方法或非静态方法

结果:会产生互斥。

解释:因为是一个对象调用,同上。


情况3:一个对象在两个线程中分别调用一个静态同步方法和一个非静态同步方法

结果:不会产生互斥。

解释:因为虽然是一个对象调用,但是两个方法的锁类型不同,调用的静态方法实际上是类对象在调用,即这两个方法产生的并不是同一个对象锁,因此不会互斥,会并发执行。


我们下面来看一道题目:

pulbic class Something(){

	public synchronized void isSyncA(){}
	
	public synchronized void isSyncB(){}
	
	public static synchronized void cSyncA(){}
	
	public static synchronized void cSyncB(){}

}

那么,加入有Something类的两个实例a与b,那么下列哪组方法可以被1个以上线程同时访问呢?

a. x.isSyncA()与 x.isSyncB()

b. x.isSyncA()与 y.isSyncA()

c. x.cSyncA()与 y.cSyncB()

d. x.isSyncA()Something.cSyncA()

这里,很清楚的可以判断:

a,都是对同一个实例的synchronized域访问,因此不能被同时访问

b,是针对不同实例的,因此可以同时被访问

c,因为是static synchronized,所以不同实例之间不会被限制

d,书上的答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。


针对上面的题目,我们来写个demo验证下:

package com.concurrent.syn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author riemann
 * @date 2019/08/11 23:40
 */
public class SynchronizedTest {

    public static SynchronizedTest staticIn = new SynchronizedTest();   //静态对象

    public synchronized void method1() {// 非静态方法1
        for (int i = 0; i < 10; i++) {
            System.out.println("method1 is running!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void method2() {// 非静态方法2
        for (int i = 0; i < 10; i++) {
            System.out.println("method2 is running!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized static void staticMethod1() {// 静态方法1
        for (int i = 0; i < 10; i++) {
            System.out.println("staticMethod1 is running!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized static void staticMethod2() {// 静态方法2
        for (int i = 0; i < 10; i++) {
            System.out.println("staticMethod2 is running!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Thread1 implements Runnable {

        @Override
        public void run() {
            SynchronizedTest.staticIn.method1();
        }

    }

    static class Thread2 implements Runnable {

        @Override
        public void run() {
            SynchronizedTest.staticIn.method2();
        }

    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Thread1());
        Thread t2 = new Thread(new Thread2());
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(t1);
        service.execute(t2);
        service.shutdown();
    }

}

(1)、a. x.isSyncA()与 x.isSyncB()

thread1:SynchronizedTest.staticIn.method1();

thread2:SynchronizedTest.staticIn.method2();

输出结果:

method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method1 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!
method2 is running!

从结果也可以验证出 a,都是对同一个实例的synchronized域访问,因此不能被同时访问。

(2)、b. x.isSyncA()与 y.isSyncA()

thread1:SynchronizedTest.staticIn.method1();

thread2:staticIn2.method1();

我了测试效果,我在另外一个实例的方法中的打印输出做了一点微调

public synchronized void method1() {// 非静态方法1
    for (int i = 0; i < 10; i++) {
        System.out.println("method1 concurrent is running!");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

输出结果:

method1 is running!
method1 concurrent is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 is running!
method1 is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 is running!
method1 concurrent is running!
method1 is running!

从结果也可以验证出 b,是针对不同实例的,因此可以同时被访问。

(3)、c. x.cSyncA()与 y.cSyncB()

thread1:SynchronizedTest.staticIn.staticMethod1();

thread2:staticIn2.staticMethod2();

在另外一个类中加上方法

public synchronized static void staticMethod2() {// 静态方法2
    for (int i = 0; i < 10; i++) {
        System.out.println("staticMethod2 concurrent is running!");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

输出结果:

staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!
staticMethod2 concurrent is running!
staticMethod1 is running!

通过结果可以验证 c,因为是static synchronized,所以不同实例之间不会被限制。

(4)、d. x.isSyncA()与y.cSyncA()

thread1:SynchronizedTest.staticIn.method2();

thread2:staticIn2.staticMethod2();

输出结果:

staticMethod2 concurrent is running!
method2 is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!
method2 is running!
staticMethod2 concurrent is running!

由结果可知 synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老周聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值