关于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方法)ide
咱们知道,当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class自己,注意:不是实例);测试
当synchronized修饰一个非static方法时,多线程下,获取的是对象锁(即类的实例对象)this
因此,当synchronized修饰一个static方法时,建立线程不论是new JoinThread()仍是new Thread(new JoinThread()),在run方法中执行inc()方法都是同步的;atom
相反,当synchronized修饰一个非static方法时,若是用new JoinThread()仍是new Thread(new JoinThread())方式建立线程,就没法保证同步操做,由于这时线程
inc()是属于对象方法,每一个线程都执有一个独立的对象实例new JoinThread(),因此多线程下执行inc()方法并不会产生互斥,也不会有同步操做。对象
另外若是考虑到变动的原子操做,可以使用atomic包下面的包装对象,这些对象都是对volatile修饰变量的一种延伸,可保证变量的原子操做而不用去同步方法或继承
代码块是否同步同步
==============================
必须注意的地方:一、某个对象实例内,synchronized aMethod(){}关键字能够防止多个线程访问对象的synchronized方法(若是一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不一样的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样能够同时访问相同类的另外一个对象实例中的synchronized方法.二、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类须要你显式的指定它的某个方法为synchronized方法;三、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块。四、尤为关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其余线程对object中全部其它synchronized(this)同步代码块的访问将被阻塞。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就得到了这个object的对象锁。结果,其它线程对该object对象全部同步代码部分的访问都被暂时阻塞。