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对象所有同步代码部分的访问都被暂时阻塞。

posted @ 2019-07-04 11:01  kissrule  阅读(245)  评论(0编辑  收藏  举报