synchronized总结

synchronized

使用方法

  1. synchronized修饰普通方法,此时锁住的是当前实例对象,进入到同步方法时,需要获取当前实例对象的锁。因此,当多线程作用于两个实例对象时,并不能保证线程安全。

  2. synchronized修饰静态方法,此时锁住的是当前类,进入同步方法时,需要获取当前类的锁。

  3. synchronized修饰代码块,此时锁住的括号中的对象,进入同步代码块时,需要获取给定对象的锁。

代码实现

  1. 作用于同一实例的普通方法
public class SynchronizedMethod {

    private int num = 0;

    synchronized public void add(String type) {

        try {

            if (type.equals("a")) {
                num = 100;
                System.out.println("set A num!");
                Thread.sleep(1000);
            } else {
                num = 200;
                System.out.println("set B num!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("set number = " + num);
    }

}

@NoArgsConstructor
public class ThreadDemo extends Thread {

    private SynchronizedMethod method;

    private String type;

    private ThisSynchronized thisSynchronized;

    private String thisType;

    public ThreadDemo(SynchronizedMethod method, String type) {
        super();
        this.method = method;
        this.type = type;
    }

    public ThreadDemo(ThisSynchronized thisSynchronized, String thisType) {
        this.thisSynchronized = thisSynchronized;
        this.thisType = thisType;
    }

    
    @Override
    public void run() {
        super.run();

        if (type != null) {
            method.add(type);
        } else if (thisType == "yes"){
            thisSynchronized.serviceMethod();
        } else if (thisType == "no") {
            thisSynchronized.serviceNumber();
        }
    }
}

/**
     * synchronized 修饰方法,调用一个对象
     */
    public static void runSynchronizedOneMethod() {
        SynchronizedMethod method = new SynchronizedMethod();

        ThreadDemo threadA = new ThreadDemo(method,"a");

        ThreadDemo threadB = new ThreadDemo(method, "b");

        threadA.start();
        threadB.start();
    }
public class SynchronizedTest {

    public static void main(String[] args) {

        /**
         *  当synchronized修饰了方法时,同步锁作用于对象,
         *  调用同一个对象,
         *  线程想要执行同步代码需要获取锁,多个线程之间存在竞争关系
         *  所以执行顺序是同步的
         */
        runSynchronizedOneMethod();
	}
}

运行结果:
在这里插入图片描述
由运行结果可知,threadA与threadB是串行运行,多个线程之间竞争的是同一个实例method的锁

  1. 作用于两个不同实例的普通方法
public static void runSychronizedMayMethod() {

        SynchronizedMethod methodA = new SynchronizedMethod();
        SynchronizedMethod methodB = new SynchronizedMethod();

        ThreadDemo threadA = new ThreadDemo(methodA,"a");

        ThreadDemo threadB = new ThreadDemo(methodB, "b");

        threadA.start();
        threadB.start();
    }

运行结果:
在这里插入图片描述
由运行结果可知,应为两个线程之间竞争的是不同实例的锁,所以两个线程是并行的,不存在竞争关系。

  1. 作用于静态方法
public static void runSychronizedStaticMethod() {

        ThreadStaticDemo threadA = new ThreadStaticDemo("A");
        threadA.setName("threadA");

        ThreadStaticDemo threadB = new ThreadStaticDemo("B");
        threadB.setName("threadB");

        threadA.start();
        threadB.start();
    }

public class ThreadStaticDemo extends Thread {
    private String type;

    public ThreadStaticDemo(String type) {
        this.type = type;
    }

    @Override
    public void run() {
        super.run();

        if (type == "A") {
            ThisSynchronized.staticServiceMethodA();
        }
        if (type == "B"){
            ThisSynchronized.staticServiceMethodB();

        }
        if (type == "classA") {
            ThisSynchronized.classServiceMethodA();
        }
        if (type == "classB") {
            ThisSynchronized.classServiceMethodB();
        }
    }
}

synchronized public static void staticServiceMethodA() {
        try {
            System.out.println(" staticServiceMethodA 当前线程名称:" + Thread.currentThread().getName() + "进入同步代码块时间:" + System.currentTimeMillis());

            Thread.sleep(1000);

            System.out.println("staticServiceMethodA 当前线程名称:" + Thread.currentThread().getName() + "离开同步代码块时间:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public static void staticServiceMethodB() {
        try {
            System.out.println(" staticServiceMethodB 当前线程名称:" + Thread.currentThread().getName() + "进入同步代码块时间:" + System.currentTimeMillis());

            Thread.sleep(1000);

            System.out.println("staticServiceMethodB 当前线程名称:" + Thread.currentThread().getName() + "离开同步代码块时间:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

运行结果:
在这里插入图片描述
由运行结果可知,由于staticServiceMethodA和staticServiceMethodB两个静态方法被synchronized修饰,两个线程竞争同一个类的锁,所以两个为串行状态。

  1. 作用于代码块
public static void runSychronizedThisMethod() {

        ThisSynchronized thisSynchronized = new ThisSynchronized();

        ThreadDemo threadA = new ThreadDemo(thisSynchronized, "yes");
        ThreadDemo threadB = new ThreadDemo(thisSynchronized, "yes");

        threadA.start();
        threadB.start();
    }
@NoArgsConstructor
public class ThreadDemo extends Thread {

    private SynchronizedMethod method;

    private String type;

    private ThisSynchronized thisSynchronized;

    private String thisType;

    public ThreadDemo(SynchronizedMethod method, String type) {
        super();
        this.method = method;
        this.type = type;
    }

    public ThreadDemo(ThisSynchronized thisSynchronized, String thisType) {
        this.thisSynchronized = thisSynchronized;
        this.thisType = thisType;
    }


    @Override
    public void run() {
        super.run();

        if (type != null) {
            method.add(type);
        } else if (thisType == "yes"){
            thisSynchronized.serviceMethod();
        } else if (thisType == "no") {
            thisSynchronized.serviceNumber();
        }
    }
}

public void serviceMethod() {

        try {

            synchronized (this) {
                System.out.println("start = " + System.currentTimeMillis());

                Thread.sleep(1000);

                System.out.println("end = " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

运行结果:
在这里插入图片描述
因为两个线程竞争的为同一个对象的锁,所以线程的运行结果为串行状态

原理

jvm基于进入和退出Monitor对象来实现方法同步和代码块的同步。代码块的同步是使用monitorenter和monitorexit指令实现的,同步方法的也是通过这两个指令实现的同步,只是在修饰方法是使用ACC_SYNCHRONIZED来代替了。

monitorenter指令是在编译后插入到同步代码开始的位置,而monitorexit是插入在方法结束活异常的位置,JVM保证这两个命令必须是配对的。每一个对象都有一个monitor与之关联,当monitor被持有后,该对象就处于锁定状态。

参考java 偏向锁、轻量级锁及重量级锁synchronized原理
Synchronize 关键字原理
Synchronize 反编译码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值