天天看点

Java并发基础

并发:多个线程操作相同的资源,保证线程安全,合理使用资源
高并发:服务能同时处理很多请求,提高程序性能 (12306抢票,双十一)

关于高并发的一些基础的概念

CPU多级缓存

Java并发基础
在Cache(高速缓存出现之后,系统变得更加复杂,高速缓存与主存之间的差异被拉大。因此出现二级缓存和三级缓存,二级缓存比高速缓存速度更慢,但空间更大。)

为什么需要CPU多级缓存?

Java并发基础
Java并发基础

缓存的意义

CPU缓存一致性(MESI)

https://www.cnblogs.com/yanlong300/p/8986041.html
Java并发基础
Java并发基础

通过这四种状态,保证多核CPU缓存之间的数据一致性

CPU乱序执行优化

乱序执行(out-of-order execution)是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。比方Core乱序执行引擎说程序某一段有7条指令,此时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路执行。 https://blog.csdn.net/andy2019/article/details/79783952

Java内存模型(Java Memory Model, JMM)

Java并发基础

左侧为jvm的内存模型,线程栈用于存放本地变量,heap用于存放对象。heap大小可变,速度较慢,线程栈速度较快,大小不变。在线程栈访问heap时,实际上先在线程栈中拥有了一份heap中对象的私有拷贝

Java并发基础

Java内存模型和硬件之间的一些对应关系

Java并发基础

Java内存模型抽象图,线程之间通讯必须经过主内存。

Java内存模型同步八种操作

(1)lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态

(2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

(3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用

(4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中

(5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎

(6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量

(7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作

(8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中

如果要把一个变量从主内存中复制到工作内存中,就需要按顺序地执行read和load操作,如果把变量从工作内存中同步到主内存中,就需要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。

同步规则

1)不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步会主内存中

2)一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或者assign)的变量。即就是对一个变量实施use和store操作之前,必须先自行assign和load操作。

3)一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。

4)如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。

5)如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。

6)对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)

Java并发基础

同步操作和规则

并发的优势与风险

Java并发基础

并发模拟工具

  • PostMan
  • apache bench
  • Jmeter
代码并发模拟
package com.ice.concurrency;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;

@Slf4j
public class ConcurrencyTest {

    public static int clientTotal = 5000;

    public static int threadTotal = 200;

    public static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for(int i = 0;i<clientTotal;i++){
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();

        log.info("count:{}",count);
    }

    private static void add(){
        count++;
    }
}