相信学习过多线程的童鞋多多少少都会用到 synchronized 关键字, 加了这个, 妈妈再也不用担心我的代码不同步了。真的是这样的么?
我们看一下下面的代码:
/**
* 验证同步锁锁住的是什么
* <p>
*
* @author YangHang
* @Date 2019年1月4日 下午11:38:01
*
*/
public class SynchronizedConfirmation {
/**
*
*/
public static void main(String[] args) {
NotSafeObject notSafeObject = new NotSafeObject();
NotSafeObject notSafeObject1 = new NotSafeObject();
Thread thread1 = new MyThread1(notSafeObject);
Thread thread2 = new MyThread2(notSafeObject1);
thread1.start();
thread2.start();
}
}
class NotSafeObject {
public synchronized void print() {
for (int i = 1; i <= 100; i++) {
out.println(Thread.currentThread().getName() + " A: " + i);
}
}
public synchronized void otherPrint() {
for (int i = 1; i <= 100; i++) {
out.println(Thread.currentThread().getName() + " B" + i);
}
}
}
/**
* 自己的线程类1
*
*/
class MyThread1 extends Thread {
private NotSafeObject notSafeObject;
// 有参构造...
public MyThread1(NotSafeObject notSafeObject) {
this.notSafeObject = notSafeObject;
}
@Override
public void run() {
notSafeObject.print();
}
}
/**
* 自己的线程类2
*
*/
class MyThread2 extends Thread {
private NotSafeObject notSafeObject;
// 有参构造...
public MyThread2(NotSafeObject notSafeObject) {
this.notSafeObject = notSafeObject;
}
@Override
public void run() {
notSafeObject.print();
}
}
点击运行得到的结果是:
我们可以看到, 运行的结果仍然是两个线程杂乱无章的交替运行中。似乎, 同步关键字并没有起作用。这是因为, 我们直接在方法上加 synchronized 关键字, 相当于用当前的对象给这段代码加了锁, 锁住的是当前这个对象。下一个线程会找当前的对象是否有被上锁, 有的话等待, 没有的话执行代码。上面的代码是有两个对象当锁, 自然不会起到同步的效果。那么, 要怎么实现全局锁呢(就是怎么来我都锁你)。两种方式加锁一种是在方法上用static synchronized加锁, 如下图:
class NotSafeObject {
public static synchronized void print() {
for (int i = 1; i <= 100; i++) {
out.println(Thread.currentThread().getName() + " A: " + i);
}
}
public static synchronized void otherPrint() {
for (int i = 1; i <= 100; i++) {
out.println(Thread.currentThread().getName() + " B" + i);
}
}
}
静态的同步, 就相当于用这个类对象加锁, 类对象是唯一的, 再来一个线程朋友来判断, 怎么的这个类对象都在上一个线程朋友手里, 因为全天下就这一个类对象。再有就是
public void print() {
synchronized (NotSafeObject.class) {
for (int i = 1; i <= 100; i++) {
out.println(Thread.currentThread().getName() + " A: " + i);
}
}
}
道理等同, 相当于也是用类对象锁住的。
以上代码的运行结果:
同步达成。
总结: synchronized 单独放到方法上或者 synchronized (this)相当于用当前的对象上锁, static synchronized 和 synchronized (***.class)相当于用类对象上锁, 不同的对象可能锁不住。但是类对象必然能锁住, 叫全局锁。
思考: 另外一个方法用同一个对象锁锁住了, 是不是也被同步了。 答案是肯定的, 因为锁的是对象, 我们是判断对象有没有锁来识别代码要不要往下走的。