精华内容
下载资源
问答
  • 一、Volatile和Synchronized区别 靠Volatile不能保证线程的安全性。(原子性) 1、Volatile轻量级,只能修饰变量。Synchronized重量级,还可以修饰方法 2、Volatile只能保证数据的可见性,不能用来同步因为多个线程...

    一、Volatile和Synchronized区别
    靠Volatile不能保证线程的安全性。(原子性)
    1、Volatile轻量级,只能修饰变量。Synchronized重量级,还可以修饰方法
    2、Volatile只能保证数据的可见性,不能用来同步因为多个线程并发访问Volatile修饰的变量不会堵塞;Synchronized不仅保证可见性,而且还保证原子性,因为只有获得了锁的线程才能进临界区从而保证临界区中所有语句都全部执行,多个线程争抢Sybchronized锁对时,会出现阻塞

    线程安全性
    线程安全性包括两个方面:原子性 可见性

    二、ThreadLoca
    2.1、 什么是ThreadLoca
    ThreadLoca提高一个线程的局部变量,访问某个线程拥有自己局部变量。当使用ThreadLoca维护变量时,ThreadLoca为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程 所对应的副本。

    class Res{
    // private int count=0;
    /*
    * 设置本地局部变量,和其他线程局部变量隔离开互不影响*/
    private ThreadLocal count=new ThreadLocal(){
    protected Integer initialValue(){
    //设置当前线程局部变量 初始化值
    return 0;
    };
    };

    public int getMun(){
      int  count =this. count.get()+1;
             this.count.set(count);
        return count;
    }
    

    }
    class ThreadLocaDemo01 extends Thread{
    private Res res;
    public ThreadLocaDemo01(Res res){
    this.res=res;
    }
    @Override

     public void run(){
        for (int i = 0; i <3 ; i++) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName()+"====i:"+i+",number:"+res.getMun());
        }
    }
    

    }
    /**

    • Created with IntelliJ IDEA.
    • @classDesc: 功能描述()
    • @Auther: 、
    • @Date: 2020/07/24/9:55
    • @Description:
      */
      public class ThreadLocaDemo {
      public static void main(String[] args) {
      Res res = new Res();
      ThreadLocaDemo01 t1 = new ThreadLocaDemo01(res);
      ThreadLocaDemo01 t2 = new ThreadLocaDemo01(res);
      ThreadLocaDemo01 t3 = new ThreadLocaDemo01(res);
      t1.start();
      t2.start();
      t3.start();
      }
      }
    展开全文
  • volatile synchronized区别   1,volatile 只是单纯的同步主存区 2,volatile 执行没有顺序,不可避免脏读(自身变量的值决定本变量的值时n=n+1、n++ 等(自运算时)) 3,都会同步主存区     用在多...

    volatile 和 synchronized区别

     

    1,volatile 只是单纯的同步主存区

    2,volatile 执行没有顺序,不可避免脏读(自身变量的值决定本变量的值时n=n+1、n++ 等(自运算时))

    3,都会同步主存区

     

     

    用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A) 

    =========================分割线1================================= 

    版权声明 :转载时请以超链接形式标明文章原始出处和作者信息及本声明 
    http://aleung.blogbus.com/logs/32090434.html 

    在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。 

    一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。以下例子展现了volatile的作用: 

    Java代码  收藏代码
    1. public class StoppableTask extends Thread {  
    2.   
    3.   private volatile boolean pleaseStop;  
    4.   
    5.   
    6.   public void run() {  
    7.   
    8.     while (!pleaseStop) {  
    9.   
    10.      // do some stuff...  
    11.   
    12.     }  
    13.   
    14.  }  
    15.   
    16.   
    17.   public void tellMeToStop() {  
    18.   
    19.    pleaseStop = true;  
    20.   
    21.   }  
    22.   
    23. }  


    假如pleaseStop没有被声明为volatile,线程执行run的时候检查的是自己的副本,就不能及时得知其他线程已经调用tellMeToStop()修改了pleaseStop的值。 

    Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。如果配合Java 5增加的atomic wrapper classes,对它们的increase之类的操作就不需要sychronized。 

    Reference: 
    http://www.javamex.com/tutorials/synchronization_volatile.shtml 
    http://www.javamex.com/tutorials/synchronization_volatile_java_5.shtml 
    http://www.ibm.com/developerworks/cn/java/j-jtp06197.html 
    =========================分割线2================================= 

      恐怕比较一下volatile和synchronized的不同是最容易解释清楚的。volatile是变量修饰符,而synchronized则作用于一段代码或方法;看如下三句get代码: 

    Java代码  收藏代码
    1. int i1;               
    2. int geti1() {return i1;}   
    3. volatile int i2;   
    4. int geti2()  
    5. {return i2;}   
    6. int i3;                
    7. synchronized int geti3() {return i3;}   
    8.   geti1()  


    得到存储在当前线程中i1的数值。多个线程有多个i1变量拷贝,而且这些i1之间可以互不相同。换句话说,另一个线程可能已经改变了它线程内的i1值,而这个值可以和当前线程中的i1值不相同。事实上,Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的i1值是1,线程1里的i1值是2,线程2里的i1值是3——这在线程1和线程2都改变了它们各自的i1值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。 
      而 geti2()得到的是“主”内存区域的i2数值。用volatile修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经 volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的,volatile修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。 
      既然volatile关键字已经实现了线程间数据同步,又要 synchronized干什么呢?呵呵,它们之间有两点不同。首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“ 主”内存区域同步整个线程的内存。因此,执行geti3()方法做了如下几步: 
    1. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放) 
    2. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗]) 
    3. 代码块被执行 
    4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值) 
    5. 线程释放监视this对象的对象锁 
      因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。 

    =========================分割线3================================= 

    volatile关键字相信了解Java多线程的读者都很清楚它的作用。volatile关键字用于声明简单类型变量,如int、float、 boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。例如,下面的例子中的n就不是原子级别的: 

    Java代码  收藏代码
    1. package  mythread;  
    2.   
    3. public   class  JoinThread  extends  Thread  
    4. {  
    5.      public   static volatile int  n  =   0 ;  
    6.     public   void  run()  
    7.     {  
    8.          for  ( int  i  =   0 ; i  <   10 ; i ++ )  
    9.              try   
    10.         {  
    11.                 n  =  n  +   1 ;  
    12.                 sleep( 3 );  //  为了使运行结果更随机,延迟3毫秒   
    13.   
    14.             }  
    15.              catch  (Exception e)  
    16.             {  
    17.             }  
    18.     }  
    19.   
    20.      public   static   void  main(String[] args)  throws  Exception  
    21.     {  
    22.   
    23.         Thread threads[]  =   new  Thread[ 100 ];  
    24.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    25.              //  建立100个线程   
    26.             threads[i]  =   new  JoinThread();  
    27.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    28.              //  运行刚才建立的100个线程   
    29.             threads[i].start();  
    30.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    31.              //  100个线程都执行完后继续   
    32.             threads[i].join();  
    33.         System.out.println( " n= "   +  JoinThread.n);  
    34.     }  
    35. }   

        
    如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面积代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作: 

    n  =  n  +   1 ; 
    n ++ ; 

          如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式: 

    Java代码  收藏代码
    1. package  mythread;  
    2.   
    3. public   class  JoinThread  extends  Thread  
    4. {  
    5.      public   static int  n  =   0 ;  
    6.   
    7.      public static   synchronized   void  inc()  
    8.     {  
    9.         n ++ ;  
    10.     }  
    11.      public   void  run()  
    12.     {  
    13.          for  ( int  i  =   0 ; i  <   10 ; i ++ )  
    14.              try   
    15.             {  
    16.                 inc();  //  n = n + 1 改成了 inc();   
    17.                 sleep( 3 );  //  为了使运行结果更随机,延迟3毫秒   
    18.   
    19.             }  
    20.              catch  (Exception e)  
    21.             {  
    22.             }  
    23.     }  
    24.   
    25.      public   static   void  main(String[] args)  throws  Exception  
    26.     {  
    27.   
    28.         Thread threads[]  =   new  Thread[ 100 ];  
    29.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    30.              //  建立100个线程   
    31.             threads[i]  =   new  JoinThread();  
    32.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    33.              //  运行刚才建立的100个线程   
    34.             threads[i].start();  
    35.          for  ( int  i  =   0 ; i  <  threads.length; i ++ )  
    36.              //  100个线程都执行完后继续   
    37.             threads[i].join();  
    38.         System.out.println( " n= "   +  JoinThread.n);  
    39.     }  
    40. }   


        上面的代码将n=n+1改成了inc(),其中inc方法使用了synchronized关键字进行方法同步。因此,在使用volatile关键字时要慎重,并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++ 等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。 

     

    展开全文
  • volatile和synchronized区别 volatile和synchronized特点 首先需要理解线程安全的两个方面:执行控制和内存可见。 执行控制的目的是控制代码执行(顺序)及是否可以并发执行。 内存可见控制的是线程执行结果在内存...

    volatile和synchronized的区别
    volatile和synchronized特点
    首先需要理解线程安全的两个方面:执行控制和内存可见。

    执行控制的目的是控制代码执行(顺序)及是否可以并发执行。

    内存可见控制的是线程执行结果在内存中对其它线程的可见性。根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷到主存。

    synchronized关键字解决的是执行控制的问题,它会阻止其它线程获取当前对象的监控锁,这样就使得当前对象中被synchronized关键字保护的代码块无法被其它线程访问,也就无法并发执行。更重要的是,synchronized还会创建一个内存屏障,内存屏障指令保证了所有CPU操作结果都会直接刷到主存中,从而保证了操作的内存可见性,同时也使得先获得这个锁的线程的所有操作,都happens-before于随后获得这个锁的线程的操作。

    volatile关键字解决的是内存可见性的问题,会使得所有对volatile变量的读写都会直接刷到主存,即保证了变量的可见性。这样就能满足一些对变量可见性有要求而对读取顺序没有要求的需求。

    使用volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性,但需要特别注意, volatile不能保证复合操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。

    在Java 5提供了原子数据类型atomic wrapper classes,对它们的increase之类的操作都是原子操作,不需要使用sychronized关键字。

    对于volatile关键字,当且仅当满足以下所有条件时可使用:

    1. 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
    2. 该变量没有包含在具有其他变量的不变式中。

    volatile和synchronized的区别
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
    volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

    展开全文
  • volatile和synchronized 区别

    千次阅读 2014-04-20 11:24:06
    1、什么是volatile Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个...

    1、什么是volatile


    Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。


    Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
    这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。


    而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互


    使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。


    由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。 


    2、volatile和synchronized 区别

    1. volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
    2. volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
    3. volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性.
    4. volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.
    5. volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化.


    引用:

    http://blog.csdn.net/majorboy/article/details/475811

    这个可能是最好的对比volatilesynchronized作用的文章了。volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。所以我们使用这两种关键字来指定三种简单的存取变量的方式。

             int i1;                       int geti1() {return i1;}

    volatile int i2;                       int geti2() {return i2;}

         int i3;          synchronized int geti3() {return i3;}

    geti1()当前线程中立即获取在i1变量中的值。线程可以获得变量的本地拷贝,而所获得的变量的值并不一定与其他线程所获得的值相同。特别是,如果其他的线程修改了i1的值,那么当前线程获得的i1的值可能与修改后的值有所差别。实际上,Java有一种主内存的机制,使用一个主内存来保存变量当前的正确的值。线程将变量的值拷贝到自己独立的内存中,而这些线程的内存拷贝可能与主内存中的值不同。所以实际当中可能发生这样的情况,在主内存中i1的值为1,线程1和线程2都更改了i1,但是却没把更新的值传回给主内存或其他线程中,那么可能在线程1i1的值为2,线程2i1的值却为3

    另一方面,geti2()可以有效的从主内存中获取i2的值。一个volatile类型的变量不允许线程从主内存中将变量的值拷贝到自己的存储空间。因此,一个声明为volatile类型的变量将在所有的线程中同步的获得数据,不论你在任何线程中更改了变量,其他的线程将立即得到同样的结果。由于线程存取或更改自己的数据拷贝有更高的效率,所以volatile类型变量在性能上有所消耗。

    那么如果volatile变量已经可以使数据在线程间同步,那么synchronizes用来干什么呢?两者有两方面的不同。首先,synchronized获取和释放由监听器控制的锁,如果两个线程都使用一个监听器(即相同对象锁),那么监听器可以强制在一个时刻只有一个线程能处理代码块,这是最一般的同步。另外,synchronized还能使内存同步。在实际当中,synchronized使得所有的线程内存与主内存相同步。所以geti3()的执行过程如下:

    1.    线程从监听器获取对象的锁。(这里假设监听器非锁,否则线程只有等到监听器解锁才能获取对象锁)

    2.    线程内存更新所有的变量,也就是说他将读取主内存中的变量使自己的变量保证有效。(JVM会使用一个“脏”标志来最优化过程,使得仅仅具有“脏”标志变量被更新。详细的情况查询JAVA规范的17.9)

    3.    代码块被执行(在这个例子中,设置返回值为刚刚从主内存重置的i3当前的值。)

    4.    任何变量的变更将被写回到主内存中。但是这个例子中geti3()没有什么变化。

    5.    线程释放对象的锁给监听器。

    所以volatile只能在线程内存和主内存之间同步一个变量的值,而synchronized则同步在线程内存和主内存之间的所有变量的值,并且通过锁住和释放监听器来实现。显然,synchronized在性能上将比volatile更加有所消耗。



    展开全文
  • volatile synchronized区别? volatile是一个类型修饰符,用来修饰被不同线程访问修改的变量,当值被一个线程更改后,该值会在缓存中更新,保持一致。 synchronized是同步锁,是LOCK的一个简化版本,性能不好,...
  • volatile和synchronized区别 volatile是变量修饰符,其修饰的变量具有可见性,Java的做法是将该变量的操作放在寄存器或者CPU缓存上进行,之后才会同步到主存,使用volatile修饰符的变量是直接读写主存,volatile不...
  • 原子性:同一时刻,只有一个线程...但是volatile只能修饰变量,synchronized可以修饰变量、代码块、方法(volatile保证变量可见性,synchronized保证代码块可见性)。 2.volatile用于解决变量多线程之间的可见性...
  • 1、Volatile变量同步机制synchronized 、Lock区别 1、volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量...
  • volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。所以我们使用这两种关键字来指定三种简单的存取变量的方式。 int i1; int geti1() {return i1;} volatile int i2; int geti2() {return i2...
  • volatile
  • synchronized 同步,解决多线程 访问临界区的问题,作用于实例 ,但是 修饰 static 方法 是 作用.class 锁 volatile 变量的线程可见,换句不太恰当的话,就是扔在了线程栈外(共享区域) volatile 实例1,这里有...
  • 1、锁提供了两种主要特性:互斥(mutual exclusion) 可见性(visibility)。 互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该...
  • 深入volatile关键字(一)并发编程的三个重要特性指令重排以及Happens-before原则 : 文章目录1 volatile关键字的语义1.1 理解volatile保证可见性1.2 理解volatile保证顺序性1.3 理解volatile不保证原子性2 内存...
  • Volatile变量同步机制synchronized 、lock区别 1、volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的...
  • 在Java中设置变量值的操作,除了longdouble...而随着JVM的成熟优化,现在在多线程环境下volatile关键字的使用变得非常重要。在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,051
精华内容 420
关键字:

volatile和synchronized区别