java synchronized
关于synchronized的初步使用,大家看拙作
关于synchronized
即可
不过今天,有个朋友问我,如果用synchronized修饰一个类的成员变量会怎么样?
咱们看下面的代码
package thread;public class ThreadTestffd { private Integer a = 0; private Integer b = 0; public static void main(String[] args) { ThreadTestffd test = new ThreadTestffd(); test.A(); test.B(); } public void A() { new Thread(new Runnable() { @Override public void run() { System.out.println("A线程准备"); synchronized (a) { System.out.println("A线程开始"); for (int i = 0; i < 10; i++) { System.out.println("a" + i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); } public void B() { new Thread(new Runnable() { @Override public void run() { System.out.println("B线程准备"); synchronized (b) { System.out.println("B线程开始"); for (int i = 0; i < 10; i++) { System.out.println("b" + i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); }}
1
最后的结果是先等a方法运行完之后,才打印出来b线程开始,当然"b线程准备"很早就打印了
这说明什么,我猜测就是:
用synchronized修饰成员变量,就直接限制了这个对象实例,synchronized(成员变量)就等于synchronized(this)
那如果有两个对象呢?
就像我把代码改成:
private Integer a = 0; private Integer b = 0; public static void main(String[] args) { ThreadTestffd test = new ThreadTestffd(); test.A(); ThreadTestffd test2 = new ThreadTestffd(); test2.B(); }
1
那结果应该是什么样的?
应该是交错打印的么?
应该是的,毕竟两个对象么
但是结果不是,结果是先打印a然后打印b
卧槽?日了狗了!
我脑子忽然想到一个问题,要不咱换一个成员变量?
private Person a=new Person(); private Person b=new Person(); public static void main(String[] args) { ThreadTestffd test = new ThreadTestffd(); test.A(); test.B(); }
1
最后的结果是交替打印,Person就是一个简单的pojo类
我靠什么情况?integer和pseron的结果不一样
后来,我忽然想到了integer是有缓存的,如下:
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
1
在-128到127直接的都是一个对象
也就是说最开始的代码,虽然一个锁a一个锁b,但是锁的都是同一个对象
后面的,把ab改成了person,就交替打印了,因为a和b压根就不是同一个对象
所以上面的结论:
用synchronized修饰成员变量,就直接限制了这个对象实例,synchronized(成员变量)就等于synchronized(this)
也是不对的
synchronized(成员变量A)与synchronized(成员变量B)是没有关系的,他们互补干扰
其实也对,既然用锁,那就一个对象么,一个a一个b什么鬼?
伙计说:我就测试测试....
其实这篇博客的名字应该叫谈谈integer的缓存的
========================================================
这里主要涉及到类对象(static方法),对象方法(非static方法)
我们知道,当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例);
当synchronized修饰一个非static方法时,多线程下,获取的是对象锁(即类的实例对象)
所以,当synchronized修饰一个static方法时,创建线程不管是new JoinThread()还是new Thread(new JoinThread()),在run方法中执行inc()方法都是同步的;
相反,当synchronized修饰一个非static方法时,如果用new JoinThread()还是new Thread(new JoinThread())方式创建线程,就无法保证同步操作,因为这时
inc()是属于对象方法,每个线程都执有一个独立的对象实例new JoinThread(),所以多线程下执行inc()方法并不会产生互斥,也不会有同步操作。
另外如果考虑到变更的原子操作,可使用atomic包下面的包装对象,这些对象都是对volatile修饰变量的一种延伸,可保证变量的原子操作而不用去同步方法或
代码块是否同步
==============================
必须注意的地方:
1、某个对象实例内,synchronized aMethod(){}关键字可以防止多个线程访问对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法.
2、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
3、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
4、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。