赞
踩
在我们日常生活中,事情应该一件一件的做,但是我们会感觉这样不仅效率低下,而且还特别累人,我们何不转换思想,看下图:
我们可以在烧开水的时候,顺便把洗茶具、拿茶叶的事情做了,这样是不是节省了好多的时间,所以并发顾名思义就是好多的线程一起在运行,那线程相关的知识,如果大家忘了,请看(线程详解)!!!
好了,言归正传,那什么是并发编程呢?
并行 :在同一个时间节点上,同时发生(是真正意义上的同时执行)
并发 :在一段时间内,对个事情交替执行
并发编程:在某些特定的场景中,有大量的请求访问同一个资源,会出现线程安全的问题,所以需要通过编程来控制解决让多个线程依次访问资源,称为并发。
以前单核CPU时,只能支持单线程模式,现在多核CPU,我们自然而然的可以支持多线程模式,在此之前,我们先浅谈下JMM(java内存模型)
java内存模型:它是java虚拟机规范的一种工作模式,将内存分为主内存和工作内存,变量数据存储在主内存中,线程在操作变量的时候会将主内存中的数据复制一份到工作内存,然后在工作内存中操作完后,再将数据写回主内存中。
多线程的出现,随之而来的也是与之对应的问题,下面我会为大家一一讲解!!!
在比赛的两头,中间隔着巨高的墙体,两位选手都风快的向终点赶去,但是墙体之隔,使他们不知道对方的存在。
可见性:多个线程分别同时对共享数据操作,彼此之间不可见,操作完写回主内存,有可能出现问题
有序性:为了性能,虚拟机对一些代码指令的执行顺序进行重排,以提高速度
- /*
- 模拟指令重排序
- */
- public class Reorder {
-
- private static int x;
- private static int y;
- private static int a;
- private static int b;
-
- public static void main(String[] args) throws InterruptedException {
- int i = 0;
- for(;;) {
- i++;
- x = 0; y = 0;
- a = 0; b = 0;
- Thread one = new Thread(new Runnable() {
- public void run() {
- a = 1;
- x = b;
- }
- });
- Thread other = new Thread(new Runnable() {
- public void run() {
- b = 1;
- y = a;
- }
- });
- one.start();
- other.start();
- one.join();
- other.join();
- String result = "第" + i + "次 (" + x + "," + y + ")";
- if(x == 0 && y == 0) {
- System.err.println(result);
- break;
- } else {
- System.out.println(result);
- }
- }
- }
- }
在运行的过程中,系统先执行了后面的代码以至于跳出循环,这就是多线程出现的第二个问题无序性
原子性:一个或多个操作在 CPU 执行的过程中不被中断的特性
两次count++,我们应该得到的是count=2,但是结果确实count=1,这就是多线程出现的问题之一(不可见性)
原因:
缓存(工作内存)带来了不可见性
指令重排优化带来了无序性
线程切换带来了非原子性
让我们接下来介绍一个关键字volatile
底层实现原理:在底层指令级别进行控制,volatile修饰的变量在操作前,添加内存屏障,不让它的指令干扰,volatile修饰的变量添加内存屏障之外,还要通过缓存一致性协议(MESI)将数据写回到主内存,其他工作内存嗅探后,把自己的工作内存数据过期,重新从主内存读取最新的数据
不可见变可见:
- public class TestVolatile {
- public static void main(String[] args) {
-
- //创建线程任务
- ThreadDemo td = new ThreadDemo();
- Thread t = new Thread(td);//创建线程
- t.start();
-
- //main线程中也需要使用flag变量
- while (true) {
- if (td.getFlag()) {//false-true
- System.out.println("main---------------");
- break;
- }
- }
- }
- }
- public class ThreadDemo implements Runnable{
-
- /*
- volatile 修饰的变量,在一个线程中被修改后,对其它线程立即可见
- 禁止cpu对指令重排序
- */
- private (volatile)选加 boolean flag = false;//共享数据
-
-
- public void run() {
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.flag = true;//让一个线程修改共享变量值
- System.out.println(this.flag);
- }
-
- public boolean getFlag() {
- return flag;
- }
-
- public void setFlag(boolean flag) {
- this.flag = flag;
- }
- }
没加volatile之前
当共享变量修改后,main方法并不知道变量已经修改,一致在重复着死循环
加volatile后
当共享变量修改后,main方法立刻知道变量已经修改,跳出死循环
无序变有序
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。