锁对象的改变

2019-03-29  本文已影响0人  迷糊小生

在前面学习完多线程的synchronized对象锁之后,不禁思考到,如果当某一线程获得某对象的对象锁后,在其内部锁对象发生了改变,这样的话对象锁还会起到作用么?

下面让我们来写个Demo测试一下:

package other.thread5;

public class DemoService {

    private String lock = "123";
    
    public void test() {
        synchronized (lock) {
            try {
                System.out.println(Thread.currentThread().getName() + "==start==" + System.currentTimeMillis());
                lock = "234";
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName() + "==end==" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        
        }
    }
    
}

首先我们创建了DemoService并且在其内部将lock改变。

public class ThreadA extends Thread{

    private DemoService service;
    public ThreadA(DemoService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        service.test();
    }
}
public class ThreadB extends Thread{

    private DemoService service;
    public ThreadB(DemoService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        service.test();
    }
}

两个简单的线程调用此方法。

public class Test {
    public static void main(String[] args) {
        try {
            DemoService service = new DemoService();
            ThreadA threadA = new ThreadA(service);
            threadA.setName("A");
            ThreadB threadB = new ThreadB(service);
            threadB.setName("B");
            threadA.start();
            Thread.sleep(200);
            threadB.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
image.png

看到此结果,明显的可以看出来线程不同步了。
让我们分析一下,当线程A首先获得了lock(123)并且进入到了同步代码块的内部,并且在其内部lock(234)对象发生了改变,然后B线程在test()方法内部也获取了一把lock(234),由于和线程A的lock(123)完全的不一致,所以B线程也就轻而易举的进入到了同步代码块里面,造成了线程不同步的结果。

那么问题来了,如果线程A和线程B同时进入到了test()方法内部,并且锁对象尚未作出改变,那么线程是否会同步呢?

下面让我们再来试验一下,将main方法中的线程睡眠200ms给去掉:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        DemoService service = new DemoService();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");
        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}
image.png

明显的可以看到AB线程之间是完全同步的,由此我们在写多线程并发代码的时候,切记不要在线程内部将对象锁给改变(特殊场景例外)

上一篇下一篇

猜你喜欢

热点阅读