synchronized关键字同步原理

本文通过示例代码详细解释了Java中同步方法和同步代码块的工作原理。同步方法通过ACC_SYNCHRONIZED标志确保线程安全,锁住的是当前类的对象。静态同步方法锁的是类本身。同步代码块则可以指定锁对象,可以通过this或者自定义对象作为锁,不同锁对象的同步代码块可并发执行。
摘要由CSDN通过智能技术生成

1.同步方法

public class Test {
    synchronized public static void testMethod(){}
    public static void main(String[] args) {
        testMethod();
    }
}
// 实现class文件的反汇编
java -c -v *.class

从字节码文件中可以看到同步方法根据flags标志中的ACC_SYNCHRONIZED来判别是否是同步方法。
在这里插入图片描述

1.1 锁对象

同步方法中并不是锁方法而是锁当前类的对象
:静态同步方法中锁是当前类,而不是对象。

  • 测试:methodA为同步方法,methodB为非同步方法,线程A调用methodA,线程B调用methodB。

TestMethod.java

public class TestMethod {

    synchronized public void methodA() {
        try {
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

ThreadA.java

public class ThreadA extends Thread{
    private TestMethod testMethod;

    public ThreadA(TestMethod testMethod) {
        super();
        this.testMethod  = testMethod;
    }
    @Override
    public void run() {
        super.run();
        testMethod.methodA();
    }
}

ThreadB.java

public class ThreadA extends Thread{
    private TestMethod testMethod;

    public ThreadA(TestMethod testMethod) {
        super();
        this.testMethod  = testMethod;
    }
    @Override
    public void run() {
        super.run();
        testMethod.methodA();
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        TestMethod testMethod = new TestMethod();
        ThreadA threadA = new ThreadA(testMethod);
        threadA.setName("a");
        ThreadB threadB = new ThreadB(testMethod);
        threadB.setName("b");
        threadA.start();
        threadB.start();

    }
}

运行结果:

methodA start ThreadName= a startTime=1690358535034
methodB start ThreadName= b startTime=1690358535034
methodA start ThreadName= a endTime=1690358540035
methodB start ThreadName= b endTime=1690358540035

结论:从结果可以看出,线程A持有TestMethod对象锁,线程B可以调用TestMethod的非同步方法。

  • 测试:methodA和methodB为同步方法,线程A调用methodA,线程B调用methodB。
    TestMethod.java
// 将methodB也修改为同步方法
public class TestMethod {

    synchronized public void methodA() {
        try {
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    synchronized public void methodB() {
        try {
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690359406773
methodA start ThreadName= a endTime=1690359411785
methodB start ThreadName= b startTime=1690359411785
methodB start ThreadName= b endTime=1690359416796

结论:从结果可以看出,线程A先持有TestMethod对象锁,虽然线程B调用的是methodB方法,但是也要等A释放锁之后才能执行。

2.同步代码块

public class Test2 {
    public void myMethod() {
        synchronized (this) {
            int age = 100;
        }
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.myMethod();
    }
}

从字节码文件中可以看到同步代码块根据monitorenter和monitorexit来进行同步处理。
在这里插入图片描述

2.1 锁对象

和同步方法一样,同步代码块synchronized (this)锁的也是对象。
测试:
TestMethod.java

public class TestMethod {

     public void methodA() {
        try {
            synchronized (this) {
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            synchronized (this) {
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690361223642
methodA start ThreadName= a endTime=1690361228654
methodB start ThreadName= b startTime=1690361228654
methodB start ThreadName= b endTime=1690361233654

:此时(this)是锁的同一对象,所以methodA和methodB同步执行,如果使用不同对象锁,则互不影响。
测试:
TestMethod.java

public class TestMethod {

	// 也可以使用非对象做为锁。
    private String lock = new String();

     public void methodA() {
        try {
            synchronized (this) {
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            synchronized (lock) {
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690361599813
methodB start ThreadName= b startTime=1690361599813
methodA start ThreadName= a endTime=1690361604820
methodB start ThreadName= b endTime=1690361604820

结论:从结果可以看出,虽然methodA和methodB中都存在同步代码块,但是因为锁对象不同,所以两个同步代码块的调用互不影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Listen·Rain

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

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

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

打赏作者

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

抵扣说明:

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

余额充值