Synchroized锁的是什么
闲来无事,写篇文章,讲讲synchronized锁的到底是什么。
1.Synchronized怎么用?
一般Synchronized有如下三种用法:
/**
* 下边两种是一样的情况
*/
synchronized (this) {
......
}
//--------------------------------------------
Object object=new Object();
synchronized (object) {
......
}
public synchronized void demoSync() {
......
}
public static synchronized void demoSync2() {
......
}
他可以在()放一个实例对象(this其实就是本对象),还可以放在静态方法上锁柱一个静态方法,还可以放在一个普通方法上锁住一个普通方法。
2.Synchronized锁的是什么?
解析完了上边的三种用法,那么这三种用法有什么区别呢,都锁的是什么?
其实synchronized最终只会锁柱两个东西:
- 对象实例
- 一个类
如果锁住静态方法也是锁的类,如果给一个普通方法上锁那么锁住的是当前的实例对象,上述代码中的第一种用法就显而易见了,如果()中放了this就是锁住的是当前的对象,如果放了其他对象那么锁的就是其他对象。我们通过jvm的基础知识可以知道一个类在jvm中如果不用多余的类加载器加载class一定是只存在一份的,但是实例对象可以存在多份。
我们来写写代码分析下这几种情况吧,先写一个类,来实现synchronized的各种用法,
class Demo1 {
private Object object;
public Demo1(Object object) {
this.object = object;
}
public synchronized void demoSync() {
while (true) {
//打印当前线程的信息
System.out.println("demoSync---------" + Thread.currentThread());
}
}
public static synchronized void demoSync2() {
while (true) {
//打印当前线程的信息
System.out.println("demoSync2------" + Thread.currentThread());
}
}
public void demoSync3() {
synchronized (this) {
while (true) {
//打印当前线程的信息
System.out.println("demoSync3---------" + Thread.currentThread());
}
}
}
public void demoSync4() {
synchronized (object) {
while (true) {
//打印当前线程的信息
System.out.println("demoSync4---------" + Thread.currentThread());
}
}
}
}
第一种情况:
public static void main(String[] args) {
//三个线程 调用 demo类的demoSync方法
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Demo1 demo1 = new Demo1();
demo1.demoSync();
}
}).start();
}
}
执行结果如下:
我们可以看到我们创建的三个线程都进去执行了,并没有达到同步的目的,这是因为每个线程都会创建一个Demo1的实例对象,然后调用每个实例对象的demoSync方法,由于锁的是本对象所以就出现了未能同步的效果。
我们进行一下反证法再去证明一下这个问题,我们对代码做如下修改:
/**
* 创建一个线程类,通过该类的构造方法将一个固定的对象传入,然后调用该对象的
* demoSync方法。
*/
class TestThread extends Thread {
private Demo1 demo1;
public TestThread(Demo1 demo1) {
this.demo1 = demo1;
}
@Override
public void run() {
demo1.demoSync();
}
}
main方法代码如下:
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
new TestThread(demo1).start();
}
我们得到的结果如图:
在图中并没其他线程进入,所以我们的修改使得代码同步了,因为此时我们保证了三个线程都是调用的同一个对象的demoSync方法。通过上边的两个代码实例我们可以看出如果synchronized修饰了一个普通方法,那么它锁住的就是本对象。
接下来我们分析下synchronized修饰静态方法的情况,我们的代码如下:
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Demo1 demo1 = new Demo1();
demo1.demoSync2();
}
}).start();
}
}
运行结果为
我们发现了只有0号线程进入了其中并没有之前的三个线程都会进入的情况,这说明,此时锁住的肯定不是当前对象了,那么它一定是锁的类,因为他只会锁两种。由此我们分析完了这种修饰静态方法的情况。它其实就相当于synchronized(Object.class)。
总结:另外的最为普通的两种方式synchronized(this)和synchronized(object)就不做多余的测试了,其实和上边的两种情况是类似的。