java IO操作和计算操作:工作内存和主内存 volatile关键字作用;原子操作对象AtomicInteger ....
应该停止但无法停止的计算线程
如下线程示例,线程实例中while循环中的条件,在主线程中通过调用实例方法更新后,while循环并没有更新判断变量是否还成立。而是陷入了while(true)死循环.
import javafx.scene.paint.Stop; /** * @ClassName ThreadMemoryModeStopFailed * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/22. */ public class ThreadMemoryModeStopFailed { private static long num = 0; private static class StopFailed implements Runnable{ private boolean shouldSTop = false; public void setShouldSTop(boolean shouldSTop) { this.shouldSTop = shouldSTop; } @Override public void run() { while (!shouldSTop){ //当注释掉IO操作System.out.println 后,就会一直卡在num++一直算不会停止 // System.out.println(Thread.currentThread().getName() + "当前时间戳"+ System.currentTimeMillis()); num++; } System.out.println("运行结束"); } } public static void main(String[] args) throws InterruptedException { StopFailed sr = new StopFailed(); Thread thread = new Thread(sr); thread.start(); Thread.sleep(1000); sr.setShouldSTop(true); System.out.println("num结果:" + num); } }
上面的代码,如果在while循环中,我们加入了一行System.out.println之后,逻辑是正常的,线程可以被停止,但是如果注释了System.out.println之后,我们仅仅保留num++,这个时候我们的程序逻辑不正常了,一直陷入while死循环计算中。没有重新读取修改后的shouldSTop变量
java的内存模型
当子线程非常消耗CPU的时候,子线程的工作内存不会主动去和主内存中的共享变量同步,这个就造成了我们刚刚出现的问题。但是当CPU消耗不是太厉害的时候,JVM会自动的把主内存中的共享变量同步到线程的工作内存中。
JVM有两种启动启动模式:
一种是client启动模式,还有之中是server启动模式。server模式启动比较慢,但是启动了之后程序的运行速度比较快,这个是因为Server模式在内存方面做优化就是上面的cache。client模式启动的时候比较快,内存使用比较少,但是程序运行的速度就比较慢
1、volatile关键字解决
volatile关键字解决工作内存和主内存变量不同步问题
private static volatile long num = 0;
我们发现子线程被停止了。这个是为什呢?volatile的作用,就是告诉我们的子线程,你在读取变量的时候,直接去主内存中读取,不要在工作内存中读取。
2、原子性操作对象,避免并发线程操作同一个对象值覆盖
volatile 关键字无法解决多线程操作同一个对象的原子性问题。原子性变量AtomicInteger 替代Integer 可以避免计算冲突错误,多线程操作此变量变为串行效果。
示例:
import java.util.concurrent.atomic.AtomicInteger; /** * @ClassName ThreadMemoryModeVolatileNotSafe * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/23. */ public class ThreadMemoryModeVolatileNotSafe { // private static volatile int num = 0; //非原子性变量 private static volatile AtomicInteger num = new AtomicInteger(0); //原子性变量 public static void main(String[] args) { Runnable r = ()->{ for(int i=0; i< 1000; i++){ // num ++; //非原子性变量 num.addAndGet(1); //原子性整数自加一 } }; for(int j=0; j<10; j++){ new Thread(r,"T"+j).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " num:" + num); /** * 非原子性变量结果:不定 * 原子性变量结果:10000 反复测试符合预期 */ } }
posted on 2021-04-22 22:57 zhangmingda 阅读(102) 评论(0) 编辑 收藏 举报