1.volatile关键字

1.volatile关键字 线程变量共享

 

/**
 * @author 
 * @date 2018/10/30 20:36
 */
public class RunThread extends Thread{
    private volatile boolean isRunning =true;
    private void setRunning(boolean isRunning){
        this.isRunning=isRunning;
    }

    public void  run(){
        System.out.println("进入run方法");
        while (isRunning==true){
           // System.out.println("---------");
        }
        System.out.println("线程停止");
    }

    public static void main(String[] args) throws InterruptedException {
        RunThread rt = new RunThread();
        rt.start();
        Thread.sleep(3000);
        rt.setRunning(false);
        System.out.println("isRunning的值已经被设置了false");
       Thread.sleep(1000);
       System.out.println(rt.isRunning);
    }
}

用volatile修饰的时候,则当变量改变的时候强制执行引擎去主内存里读取

如果不用volatile修饰, java会为每个线程开辟单独的空间,设置了isrunning后,会无效。 线程不会停止

发现了一个奇怪的问题:

当里面放了一个输出语句的时候,线程会停止。 

package com.wq.thread01;

import com.sun.org.apache.xpath.internal.WhitespaceStrippingElementMatcher;

/**
 * @author
 * @date 2018/12/13 18:21
 */
public class RunThread extends Thread{

    /**
     *isRunning 加了volatile关键字就会保证isRunning在线程之间的可见性 改了立马可见
     */
    private volatile boolean isRunning=true;
    public void setRunning(boolean isRunning){
        this.isRunning=isRunning;
    }

    @Override
    public void run() {
        System.out.println("进入run方法");
        while (isRunning==true){
           /*for (int i=0;i<=10000;i++){
               int a=i;
           }*/
            System.out.print("");
        }
        System.out.println("线程停止");
    }


    public static void main(String[] args) throws InterruptedException {
        RunThread rt = new RunThread();
        rt.start();
        Thread.sleep(3000);
        rt.setRunning(false);
        System.out.println("isrunng的值已经设置了false");
    }
}

这是为什么 百度了一下。 不知道正确性:

如上面所示,加了System.out.println之后,线程能停止了。有的人会说,println的源码里面有synchronized关键字,所以会同步变量stopRequested的值。这种是很不正确的理解,同步关键字同步的是同步块里面的变量,stop在这个同步代码块之外。
真正的原因是这样的:JVM会尽力保证内存的可见性,即便这个变量没有加同步关键字。换句话说,只要CPU有时间,JVM会尽力去保证变量值的更新。这种与volatile关键字的不同在于,volatile关键字会强制的保证线程的可见性。而不加这个关键字,JVM也会尽力去保证可见性,但是如果CPU一直有其他的事情在处理,它也没办法。最开始的代码,一直处于试了循环中,CPU处于一直被饱受占用的时候,这个时候CPU没有时间,JVM也不能强制要求CPU分点时间去取最新的变量值。而加了System.out.println之后,由于内部代码的同步关键字的存在,导致CPU的输出其实是比较耗时的。这个时候CPU就有可能有时间去保证内存的可见性,于是while循环可以被终止。

其实,也可以在while循环里面加上sleep,让run方法放弃cpu,但是不放弃锁,这个时候由于CPU有空闲的时候就去按照JVM的要求去保证内存的可见性。如下图所示。  run方法里面休息了3秒,cpu有充足的空闲时间去取变量的最新值,所以循环执行一次就停止了。

 

1.volatile有可见性 但没有原子性

 

package com.wq.thread01;

import java.util.concurrent.atomic.AtomicInteger;

/**volatile有可见性 但没有原子性
 *
 *
 * @author 
 * @date 2018/12/13 19:14
 */
public class VolatileNoAtomic extends Thread {
    private static volatile  int count;
    //AtomicInteger有原子性
   // private  static AtomicInteger count =new AtomicInteger(0);
    private static  void addCount(){
        //多个线程调用count++,没有原子性 会出现问题 用atomicInteger
        for (int i = 0; i <1000 ; i++) {
          count++;
         //   count.incrementAndGet();
        }
        System.out.println(count);
    }

    public void  run(){
            addCount();
    }


    public static void main(String[] args) {
        VolatileNoAtomic[] arr = new VolatileNoAtomic[10];
        for (int i = 0; i <10 ; i++) {
            arr[i] = new VolatileNoAtomic();
        }
        for (int i = 0; i < 10; i++) {
            arr[i].start();
        }
    }
}

结果:

最后一个不是10000, 

package com.wq.thread01;

import java.util.concurrent.atomic.AtomicInteger;

/**volatile有可见性 但没有原子性
 *
 *
 * @author wangqiang
 * @date 2018/12/13 19:14
 */
public class VolatileNoAtomic extends Thread {
    //private static volatile  int count;
    //AtomicInteger有原子性
   private  static AtomicInteger count =new AtomicInteger(0);
    private static  void addCount(){
        //多个线程调用count++,没有原子性 会出现问题 用atomicInteger
        for (int i = 0; i <1000 ; i++) {
         // count++;
          count.incrementAndGet();
        }
        System.out.println(count);
    }

    public void  run(){
            addCount();
    }


    public static void main(String[] args) {
        VolatileNoAtomic[] arr = new VolatileNoAtomic[10];
        for (int i = 0; i <10 ; i++) {
            arr[i] = new VolatileNoAtomic();
        }
        for (int i = 0; i < 10; i++) {
            arr[i].start();
        }
    }
}

用了AtomicInteger输出结果最后一个是10000。

多个线程调用count++,没有原子性 会出现问题 用atomicInteger

3.多个addandget在一个方法内是 非 原子性的,需要加synchronized进行装饰,保证集体原子性

package com.wq.thread01;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wangqiang
 * @date 2018/12/13 19:39
 */
public class AtomicUse {
    private static  AtomicInteger count = new AtomicInteger(0);

    //多个addandget在一个方法内是 非 原子性的,需要加synchronized进行装饰,保证4个集体原子性

    public synchronized int multiAdd(){

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count.addAndGet(1);
        count.addAndGet(2);
        count.addAndGet(3);
        count.addAndGet(4);

        return count.get();
    }


    public static void main(String[] args) {
      final   AtomicUse au = new AtomicUse();

       List<Thread> ts = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            ts.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(au.multiAdd());
                }
            }));
        }

        for (Thread t: ts){
            t.start();
        }
    }
}

注意以上三点

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值