java synchronized

来源:互联网 发布:身份鉴权超时cms 编辑:程序博客网 时间:2024/05/22 13:45
synchronized  / 

'sɪŋkrənaɪzd/


Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

看如下代码 :

class T {        public  static  boolean asleep = false;          public  static  int  count = 1 ;            public static void main(String[] args) throws InterruptedException {          for (int i = 0; i < 4; i++) {              new Thread(new Runnable() {                  @Override                  public void run() {                        Test();                  }              }).start();          }          Thread.sleep(3000);          asleep = true;                         System.out.println("end");        }        public static  void Test( ) {          while (!asleep) {              try {                  Thread.sleep(500);              } catch (InterruptedException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              }              Add();          }      }        public  static void Add() {          count++;        System.out.println("@===i=="+count);            }  }  
运行效果如下:



可以发现在多线程下 打印出来的 i++ 并不是依次相加的 为什么会出现这种情况呢 ?这个是由于线程内部变量副本引起的。

当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。如下图:



read and load 从主存复制变量到当前工作内存
use and assign  执行代码,改变共享变量值 
store and write 用工作内存数据刷新主存相关内容

其中use and assign 可以多次出现

但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果不会依次相加。

为了防指多线程加载同一count值。只需要在Add()方法前加上  synchronized  就ok了 

    public synchronized  static void Add() {      count++;        System.out.println("@===i=="+count);            }  


运行结果 :













0 0
原创粉丝点击