• 架构师养成记--4.volatile关键字


    volatile修饰的变量可在多个线程间可见。

    如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本。

     1 public class RunThread extends Thread{
     2 
     3     private volatile boolean isRunning = true;
     4     private void setRunning(boolean isRunning){
     5         this.isRunning = isRunning;
     6     }
     7     
     8     public void run(){
     9         System.out.println("进入run方法..");
    10         int i = 0;
    11         while(isRunning == true){
    12             //..
    13         }
    14         System.out.println("线程停止");
    15     }
    16     
    17     public static void main(String[] args) throws InterruptedException {
    18         RunThread rt = new RunThread();
    19         rt.start();
    20         Thread.sleep(1000);
    21         rt.setRunning(false);
    22         System.out.println("isRunning的值已经被设置了false");
    23     }
    24     
    25     
    26 }
    View Code

    那么如何达到预期效果让子线程停止呢?那就是变量isRunning使用volatile修饰,原理如下图

     

     需要注意的一点是,volatile关键字修饰的变量只有可见性,没有原子性。如下代码,如果使用第九行代码的话最终打印结果不是10000

     1 import java.util.concurrent.atomic.AtomicInteger;
     2 
     3 /**
     4  * volatile关键字不具备synchronized关键字的原子性(同步)
     5  * @author alienware
     6  *
     7  */
     8 public class VolatileNoAtomic extends Thread{
     9     //private static volatile int count;
    10     private static AtomicInteger count = new AtomicInteger(0);
    11     private static void addCount(){
    12         for (int i = 0; i < 1000; i++) {
    13             //count++ ;
    14             count.incrementAndGet();
    15         }
    16         System.out.println(count);
    17     }
    18     
    19     public void run(){
    20         addCount();
    21     }
    22     
    23     public static void main(String[] args) {
    24         
    25         VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
    26         for (int i = 0; i < 10; i++) {
    27             arr[i] = new VolatileNoAtomic();
    28         }
    29         
    30         for (int i = 0; i < 10; i++) {
    31             arr[i].start();
    32         }
    33     }
    34     
    35     
    36     
    37     
    38 }
    View Code

    那么如何才能有原子性呢?可以对对象进行AtimicInteger  修饰

    多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 import java.util.concurrent.atomic.AtomicInteger;
     4 
     5 public class AtomicUse {
     6 
     7     private static AtomicInteger count = new AtomicInteger(0);
     8     
     9     //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
    10     /**synchronized*/
    11     public synchronized int multiAdd(){
    12             try {
    13                 Thread.sleep(100);
    14             } catch (InterruptedException e) {
    15                 e.printStackTrace();
    16             }
    17             count.addAndGet(1);
    18             count.addAndGet(2);
    19             count.addAndGet(3);
    20             count.addAndGet(4); //+10
    21             return count.get();
    22     }
    23     
    24     
    25     public static void main(String[] args) {
    26         
    27         final AtomicUse au = new AtomicUse();
    28 
    29         List<Thread> ts = new ArrayList<Thread>();
    30         for (int i = 0; i < 100; i++) {
    31             ts.add(new Thread(new Runnable() {
    32                 @Override
    33                 public void run() {
    34                     System.out.println(au.multiAdd());
    35                 }
    36             }));
    37         }
    38 
    39         for(Thread t : ts){
    40             t.start();
    41         }
    42 
    43 
    44     
    45         
    46 
    47         
    48     }
    49 }
    View Code
  • 相关阅读:
    CUP的MESI协议
    synchronized 锁的升级
    BigDecimal/Long 前后端交互失去精度解决办法
    nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
    根据文件原始名称,文件根路径按照日期生成存储路径
    异步处理MultipartFile -- No such file or directory
    select下拉框相关操作(更新中。。。)
    input清空和重置select下拉框
    sql多字段分组排序显示全部数据
    ajax发送请求下载字节流形式的excel文件
  • 原文地址:https://www.cnblogs.com/sigm/p/6132416.html
Copyright © 2020-2023  润新知