在前面学习完多线程的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线程之间是完全同步的,由此我们在写多线程并发代码的时候,切记不要在线程内部将对象锁给改变(特殊场景例外)
网友评论