synchronized关键字
事实上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。
synchronized修饰非静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。
1、对象方法锁
我们先看看非线程安全实例(Run.java):
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef);
athread.start();
ThreadB bthread = new ThreadB(numRef);
bthread.start();
实验结论:两个线程访问同一个对象中的同步方法是一定是线程安全的。
这里线程获取的是HasSelfPrivateNum的对象实例的锁——对象锁。
HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef1);
athread.start();
ThreadB bthread = new ThreadB(numRef2);
bthread.start();
这里是非同步的,因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系。
因此,出现非同步的结果。
2、同步块synchronized (this)
这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。
需要注意的是synchronized (){}的{}前后的代码依旧是异步的。
3、synchronized (非this对象)
这里线程争夺的是synchronized把持的对象锁,两个线程有竞争同一对象锁的关系,出现同步
现在有一个问题:一个类里面有两个非静态同步方法,会有影响么?
答案是:如果对象实例A,线程1获得了对象A的对象锁,那么其他线程就不能进入需要获得对象实例A的对象锁才能访问的同步代码(包括同步方法和同步块)。不理解可以细细品味一下!
4、静态synchronized同步方法
两个线程在争夺同一个类锁,因此同步。
5、synchronized (class)
两个线程依旧在争夺同一个类锁,因此同步
需要特别说明:对于同一个类A,线程1争夺A对象实例的对象锁,线程2争夺类A的类锁,这两者不存在竞争关系。也就说对象锁和类锁互补干预内政
静态方法则一定会同步,非静态方法需在单例模式才生效,但是也不能都用静态同步方法,总之用得不好可能会给性能带来极大的影响。