长文慎入-探索Java并发编程与高并发解决方案

所有示例代码,请见/下载于
https://github.com/Wasabi1234/concurrency


#1 基本概念
##1.1 并发
同时拥有两个或者多个线程,如果程序在单核处理器上运行多个线程将交替地换入或者换出内存,这些线程是同时“存在"的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核上,因此可以同时运行.
##1.2 高并发( High Concurrency)
互联网分布式系统架构设计中必须考虑的因素之一,通常是指,通过设计保证系统能够同时并行处理很多请求.
##1.3 区别与联系

  • 并发: 多个线程操作相同的资源,保证线程安全,合理使用资源
  • 高并发:服务能同时处理很多请求,提高程序性能
    #2 CPU
    ##2.1 CPU 多级缓存
  • 为什么需要CPU cache
    CPU的频率太快了,快到主存跟不上
    如此,在处理器时钟周期内,CPU常常需要等待主存,浪费资源。所以cache的出现,是为了缓解CPU和内存之间速度的不匹配问题(结构:cpu-> cache-> memory ).
  • CPU cache的意义
    1) 时间局部性
    如果某个数据被访问,那么在不久的将来它很可能被再次访问
    2) 空间局部性
    如果某个数据被访问,那么与它相邻的数据很快也可能被访问
    ##2.2 缓存一致性(MESI)
    用于保证多个 CPU cache 之间缓存共享数据的一致
  • M-modified被修改
    该缓存行只被缓存在该 CPU 的缓存中,并且是被修改过的,与主存中数据是不一致的,需在未来某个时间点写回主存,该时间是允许在其他CPU 读取主存中相应的内存之前,当这里的值被写入主存之后,该缓存行状态变为 E
  • E-exclusive独享
    缓存行只被缓存在该 CPU 的缓存中,未被修改过,与主存中数据一致
    可在任何时刻当被其他 CPU读取该内存时变成 S 态,被修改时变为 M态
  • S-shared共享
    该缓存行可被多个 CPU 缓存,与主存中数据一致
  • I-invalid无效
  • 乱序执行优化
    处理器为提高运算速度而做出违背代码原有顺序的优化
    ##并发的优势与风险

    #3 项目准备
    ##3.1 项目初始化



    ##3.2 并发模拟-Jmeter压测





    ##3.3 并发模拟-代码
    ###CountDownLatch

    ###Semaphore(信号量)

    以上二者通常和线程池搭配

下面开始做并发模拟

package com.mmall.concurrency;

import com.mmall.concurrency.annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author shishusheng
 * @date 18/4/1
 */
@Slf4j
@NotThreadSafe
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 Exception {
        //定义线程池
        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 (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        //关闭线程池
        executorService.shutdown();
        log.info("count:{}", count);
    }

    /**
     * 统计方法
     */
    private static void add() {
        count++;
    }
}

运行发现结果随机,所以非线程安全
#4线程安全性
##4.1 线程安全性
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的
##4.2 原子性
###4.2.1 Atomic 包

  • AtomicXXX:CAS,Unsafe.compareAndSwapInt
    提供了互斥访问,同一时刻只能有一个线程来对它进行操作

    
    package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;

/**

  • @author shishushengbr/>*/
    @Slf4j
    @ThreadSafe
    public class AtomicExample2 {

    /**

    • 请求总数
      */
      public static int clientTotal = 5000;

    /**

    • 同时并发执行的线程数
      */
      public static int threadTotal = 200;

    /**

    • 工作内存
      */
      public static AtomicLong count = new AtomicLong(0);

    public static void main(String[] args) throws Exception {
    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 {
    System.out.println();
    semaphore.acquire();
    add();
    semaphore.release();
    } catch (Exception e) {
    log.error("exception", e);
    }
    countDownLatch.countDown();
    });
    }
    countDownLatch.await();
    executorService.shutdown();
    //主内存
    log.info("count:{}", count.get());
    }

    private static void add() {
    count.incrementAndGet();
    // count.getAndIncrement();
    }
    }

package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author shishusheng
 * @date 18/4/3
 */
@Slf4j
@ThreadSafe
public class AtomicExample4 {

    private static AtomicReference<Integer> count = new AtomicReference<>(0);

    public static void main(String[] args) {
        // 2
        count.compareAndSet(0, 2);
        // no
        count.compareAndSet(0, 1);
        // no
        count.compareAndSet(1, 3);
        // 4
        count.compareAndSet(2, 4);
        // no
        count.compareAndSet(3, 5);
        log.info("count:{}", count.get());
    }
}

  • AtomicReference,AtomicReferenceFieldUpdater
  • AtomicBoolean
  • AtomicStampReference : CAS的 ABA 问题
    ###4.2.2 锁
    synchronized:依赖 JVM
  • 修饰代码块:大括号括起来的代码,作用于调用的对象
  • 修饰方法: 整个方法,作用于调用的对象
  • 修饰静态方法:整个静态方法,作用于所有对象
    
    package com.mmall.concurrency.example.count;

import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**

Lock: 依赖特殊的 CPU 指令,代码实现
###4.2.3 对比

  • synchronized: 不可中断锁,适合竞争不激烈,可读性好
  • Lock: 可中断锁,多样化同步,竞争激烈时能维持常态
  • Atomic: 竞争激烈时能维持常态,比Lock性能好; 只能同步一
    个值
    ##4.3 可见性
    一个线程对主内存的修改可以及时的被其他线程观察到
    ###4.3.1 导致共享变量在线程间不可见的原因
  • 线程交叉执行
  • 重排序结合线程交叉执行
  • 共享变量更新后的值没有在工作内存与主存间及时更新
    ###4.3.2 可见性之synchronized
    JMM关于synchronized的规定
  • 线程解锁前,必须把共享变量的最新值刷新到主内存
  • 线程加锁时,将清空工作内存中共享变量的值,从而使
    用共享变量时需要从主内存中重新读取最新的值(加锁与解锁是同一把锁)
    ###4.3.3 可见性之volatile
    通过加入内存屏障和禁止重排序优化来实现
  • 对volatile变量写操作时,会在写操作后加入一条store
    屏障指令,将本地内存中的共享变量值刷新到主内存
  • 对volatile变量读操作时,会在读操作前加入一条load
    屏障指令,从主内存中读取共享变量


  • volatile使用
    
    volatile boolean inited = false;

//线程1:
context = loadContext();
inited= true;

// 线程2:
while( !inited ){
sleep();
}
doSomethingWithConfig(context)


##4.4 有序性
一个线程观察其他线程中的指令执行顺序,由于指令重排序的存在,该观察结果一般杂乱无序

JMM允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性
###4.4.1 happens-before 规则
#5发布对象
![](https://upload-images.jianshu.io/upload_images/4685968-ed313a1caed24223.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![发布对象](https://upload-images.jianshu.io/upload_images/4685968-b368f6fe5b350cbe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![对象逸出](https://upload-images.jianshu.io/upload_images/4685968-88d207fcc6bf1866.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##5.1 安全发布对象
![](https://upload-images.jianshu.io/upload_images/4685968-7400ab2abe1dbbfb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![非线程安全的懒汉模式](https://upload-images.jianshu.io/upload_images/4685968-ba18bdbe3a3c4ed1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![饿汉模式](https://upload-images.jianshu.io/upload_images/4685968-be2854c290143094.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![线程安全的懒汉模式](https://upload-images.jianshu.io/upload_images/4685968-e632243a5a97281a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

package com.mmall.concurrency.example.singleton;

import com.mmall.concurrency.annoations.NotThreadSafe;

/**

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**

}


#9 线程池
##9.1 newCachedThreadPool
![](https://upload-images.jianshu.io/upload_images/4685968-1122da7a48223ba1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##9.2 newFixedThreadPool
![](https://upload-images.jianshu.io/upload_images/4685968-0ea942bf12e5210f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##9.3 newSingleThreadExecutor
看出是顺序执行的
![](https://upload-images.jianshu.io/upload_images/4685968-989d59429f589403.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##9.4 newScheduledThreadPool
![](https://upload-images.jianshu.io/upload_images/4685968-f7536ec7a1cf6ecc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/4685968-c90e09d5bfe707e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#10 死锁
![](https://upload-images.jianshu.io/upload_images/4685968-461f6a4251ae8ca4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/4685968-46d58773e597195f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

长文慎入-探索Java并发编程与高并发解决方案

原文地址:http://blog.51cto.com/13601128/2337470

时间: 2024-08-02 11:00:24

长文慎入-探索Java并发编程与高并发解决方案的相关文章

Java并发编程与高并发解决方案

第1章 课程准备   1-1 课程导学    1-2 并发编程初体验   1-3 并发与高并发基本概念第2章 并发基础   2-1 CPU多级缓存-缓存一致性   2-2 CPU多级缓存-乱序执行优化   2-3 JAVA内存模型    2-4 并发的优势与风险第3章 项目准备   3-1 案例环境初始化   3-2 案例准备工作    3-3 并发模拟-工具   3-4 并发模拟-代码 第4章 线程安全性   4-1 线程安全性-原子性-atomic-1    4-2 线程安全性-原子性-at

【并发编程】高并发相关技术

高并发之扩容思路 垂直扩容(纵向扩展):提高系统部件能力 水平扩容(横向扩展):增加更多系统成员来实现 读操作扩展:memcache.redis.CDN等缓存 写操作扩展:Cassandra.Hbase等 高并发之缓存思路 缓存特征 命中率:命中数/(命中数+未命中数) 最大元素(空间) 清空策略:FIFO, LFU, LRU, 过期时间,随机等 缓存命中率影响因素 业务场景和业务需求 缓存的设计(粒度和策略) 缓存容量和基础设施 缓存分类和应用场景 本地缓存:编程实现(成员变量.局部变量.静态

Java大型互联网-构建高并发和高可用的电商平台架构实践原理

并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. "高可用性"(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性. 一. 设计理念 1. 空间换时间 多级缓存,静态化 客户端页面缓存(http header中包含Expires/Cache of Control,last modified(304,server不返

并发编程专题(一)-并发与多线程

1.并发 1.1 并发与并行 首先介绍一下并发与并行,两者虽然只有一字之差,但实际上却有着本质的区别,其概念如下: 并行性(parallel):指在同一时刻,有多条指令在多个处理器上同时执行: 并发性(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果. 在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不

从零探索Java网络编程01之 TCP/IP 与 Socket

最近完成了几项比较简单的项目, 日子有些松散, 终于是在996里偷了点闲暇时光, 想着来研究研究些啥吧?  一个普通的控制台日志映入了我的眼帘(孽缘呀): (图中使用 SpringBoot 的 log4j 来输出日志, logginglevel: debug, jdk版本为1.8) 造成这种现象的原因可能是, Mybatis在执行接口方法时, 实例化了多个Preparedstatement, 启用了不同的NIO线程, 但是其中, 咦?! 没错, NIO中出了一段IO!!! (天哪!), 在查询网

JAVA中怎么处理高并发的情况

一.背景综述 并发就是可以使用多个线程或进程,同时处理(就是并发)不同的操作. 高并发的时候就是有很多用户在访问,导致系统数据不正确.糗事数据的现象.对于一些大型网站,比如门户网站,在面对大量用户访问.高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器.高性能的数据库.高效率的编程语言.还有高性能的Web容器.这几个解决思路在一定程度上意味着更大的投入. 使用一般的synchronized或者是lock或者是队列都是无法满足高并发的问题. 二.解决方法有三: 1.使用缓存 2.

java SE程序关于高并发的注意事项

最近做一个java SE程序.使用线程池进行高并发任务的处理.其中任务处理过程中会有查询数据库操作,导致任务处理非常迟缓.于是在网上查找资料.最终解决现在把有关的注意事项进行总结.一.关于线程池的注意事项.对于多个任务,线程池最好不要公用.应该把线程池分开关于线程池的代码 </pre><pre code_snippet_id="547077" snippet_file_name="blog_20141209_1_7940215" name=&quo

java架构师,高并发,分布式,集群,大型高并发电商项目实战视频教程

15套java架构师.集群.高可用.高可扩展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布式项目实战视频教程 视频课程内容包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Redis.ActiveMQ.Nginx.Mycat.Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.性能调优.高并发.to

16套java架构师,高并发,高可用,高性能,集群,大型分布式电商项目实战视频教程

16套Java架构师,集群,高可用,高可扩展,高性能,高并发,性能优化,设计模式,数据结构,虚拟机,微服务架构,日志分析,工作流,Jvm,Dubbo ,Spring boot,Spring cloud, Redis,ActiveMQ,Nginx,Mycat,Netty,Jvm,Mecached,Nosql,Spring,大型分布式项目实战视频教程 视频课程包含: 高级Java架构师包含:架构师,高并发,分布式,集群,高可用,高可扩展,高性能,设计模式,数据结构算法,虚拟机,微服务架构,日志分析,