文章目录
- 注意一个问题如果多个线程同时持有锁对象, 且同时持有的是相同的锁对象, 那么这些线程之间的任务就是同步的, 如果分别持有不同的锁对象, 那么就是异步的.
字符串对象的改变
public class MyService {
private String lock = "123";
public void testMethod() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " begin at: "
+ System.currentTimeMillis());
lock = "456";
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end at: "
+ System.currentTimeMillis());
}
}
}
public class Run2 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
Thread t1 = new Thread("A") {
@Override
public void run() {
service.testMethod();
}
};
Thread t2 = new Thread("B") {
@Override
public void run() {
service.testMethod();
}
};
t1.start();
//关键点 这里等待0.1秒, A线程等待2秒
Thread.sleep(100);
t2.start();
}
}
- 运行结果
- 此时我们发现A和B俩个线程是A获得锁进入之后过了100秒后B也获得锁进入了, 但是此时A并没有出去, 也就是A并没有释放锁, 究其原因就是A进入之后再0.1秒内修改了lock这个对象, 要知道字符串类型"123"和"456"是俩个不同的类型, 所以才会有这样的现象, 如果我们不让等待那0.1秒, 就不会出现这样的问题
- 注释掉后就不会有这样的问题
- 此时A和B差不多是同时要求启动, 俩个线程之间一开始竞争的还是"123"这把锁, 虽然将锁改成"456" , 但结果还是异步的, 因为共同争抢的锁是"123"
对象属性的改变
public class User {
public String name;
public int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Service {
public void testMethod(User user) {
synchronized (user) {
System.out.println(Thread.currentThread().getName() + " begin: " +
System.currentTimeMillis());
//修改信息
user.age = 99;
user.name = "HaHa";
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end: " +
System.currentTimeMillis());
}
}
}
public class Run3 {
public static void main(String[] args) throws InterruptedException {
User user = new User("listen", 20);
Service service = new Service();
Thread t1 = new Thread("A") {
@Override
public void run() {
service.testMethod(user);
}
};
Thread t2 = new Thread("B") {
@Override
public void run() {
service.testMethod(user);
}
};
t1.start();
//关键点
Thread.sleep(100);
t2.start();
}
}
- 运行结果
- 这个代码我们发现, 只要对象不变, 即使属性被改变, 运行的结果还是同步的