万字总结!全网最全的Java并发编程知识点

运行发现结果随机,所以非线程安全

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 JavaEdge

*/

@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();

}

}

@Slf4j

@ThreadSafe

public class AtomicExample4 {

private static AtomicReference 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;

/**

  • @author JavaEdge

*/

@Slf4j

@ThreadSafe

public class CountExample3 {

/**

  • 请求总数

*/

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 synchronized static void add() {

count++;

}

}

synchronized 修正计数类方法

  • 修饰类:括号括起来的部分,作用于所有对象

子类继承父类的被 synchronized 修饰方法时,是没有 synchronized 修饰的!!!

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 读

计数类之 volatile 版,非线程安全的

  • 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发布对象

====================================================================

  • 发布对象

使一个对象能够被当前范围之外的代码所使用

  • 对象逸出

一种错误的发布。当-个对象还没有构造完成时,就使它被其他线程所见

发布对象

对象逸出

5.1 安全发布对象


  • 在静态初始化函数中初始化一个对象引用

  • 将对象的引用保存到volatile类型域或者AtomicReference对象中

  • 将对象的引用保存到某个正确构造对象的final类型域中

  • 将对象的引用保存到一个由锁保护的域中

非线程安全的懒汉模式

饿汉模式

线程安全的懒汉模式

package com.mmall.concurrency.example.singleton;

import com.mmall.concurrency.annoations.NotThreadSafe;

/**

  • 懒汉模式 -》 双重同步锁单例模式

  • 单例实例在第一次使用时进行创建

  • @author JavaEdge

*/

@NotThreadSafe

public class SingletonExample4 {

/**

  • 私有构造函数

*/

private SingletonExample4() {

}

// 1、memory = allocate() 分配对象的内存空间

// 2、ctorInstance() 初始化对象

// 3、instance = memory 设置instance指向刚分配的内存

// JVM和cpu优化,发生了指令重排

// 1、memory = allocate() 分配对象的内存空间

// 3、instance = memory 设置instance指向刚分配的内存

// 2、ctorInstance() 初始化对象

/**

  • 单例对象

*/

private static SingletonExample4 instance = null;

/**

  • 静态的工厂方法

  • @return

*/

public static SingletonExample4 getInstance() {

// 双重检测机制 // B

if (instance == null) {

// 同步锁

synchronized (SingletonExample4.class) {

if (instance == null) {

// A - 3

instance = new SingletonExample4();

}

}

}

return instance;

}

}

7 AQS

====================================================================

7.1 介绍


数据结构

  • 使用Node实现FIFO队列,可以用于构建锁或者其他同步装置的基础框架

  • 利用了一个int类型表示状态

  • 使用方法是继承

  • 子类通过继承并通过实现它的方法管理其状态{acquire 和release} 的方法操纵状态

  • 可以同时实现排它锁和共享锁模式(独占、共享)

同步组件

CountDownLatch

package com.mmall.concurrency.example.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

  • @author JavaEdge

*/

@Slf4j

public class CountDownLatchExample1 {

private final static int threadCount = 200;

public static void main(String[] args) throws Exception {

ExecutorService exec = Executors.newCachedThreadPool();

final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++) {

final int threadNum = i;

exec.execute(() -> {

try {

test(threadNum);

} catch (Exception e) {

log.error(“exception”, e);

} finally {

countDownLatch.countDown();

}

});

}

countDownLatch.await();

log.info(“finish”);

exec.shutdown();

}

private static void test(int threadNum) throws Exception {

Thread.sleep(100);

log.info(“{}”, threadNum);

Thread.sleep(100);

}

}

package com.mmall.concurrency.example.aqs;

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;

/**

  • 指定时间内处理任务

  • @author JavaEdge

*/

@Slf4j

public class CountDownLatchExample2 {

private final static int threadCount = 200;

public static void main(String[] args) throws Exception {

ExecutorService exec = Executors.newCachedThreadPool();

final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++) {

final int threadNum = i;

exec.execute(() -> {

try {

test(threadNum);

} catch (Exception e) {

log.error(“exception”, e);

} finally {

countDownLatch.countDown();

}

});

}

countDownLatch.await(10, TimeUnit.MILLISECONDS);

log.info(“finish”);

exec.shutdown();

}

private static void test(int threadNum) throws Exception {

Thread.sleep(100);

log.info(“{}”, threadNum);

}

}

##Semaphore用法

CycliBarrier


package com.mmall.concurrency.example.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

  • @author JavaEdge

*/

@Slf4j

public class CyclicBarrierExample1 {

private static CyclicBarrier barrier = new CyclicBarrier(5);

public static void main(String[] args) throws Exception {

ExecutorService executor = Executors.newCachedThreadPool();

for (int i = 0; i < 10; i++) {

final int threadNum = i;

Thread.sleep(1000);

executor.execute(() -> {

try {

race(threadNum);

} catch (Exception e) {

log.error(“exception”, e);

}

});

}

executor.shutdown();

}

private static void race(int threadNum) throws Exception {

Thread.sleep(1000);

log.info(“{} is ready”, threadNum);

barrier.await();

log.info(“{} continue”, threadNum);

}

}

package com.mmall.concurrency.example.aqs;

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;

/**

  • @author JavaEdge

*/

@Slf4j

public class CyclicBarrierExample2 {

private static CyclicBarrier barrier = new CyclicBarrier(5);

public static void main(String[] args) throws Exception {

ExecutorService executor = Executors.newCachedThreadPool();

for (int i = 0; i < 10; i++) {

final int threadNum = i;

Thread.sleep(1000);

executor.execute(() -> {

try {

race(threadNum);

} catch (Exception e) {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

面试资料整理汇总

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。

面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了

在这里祝大家能够拿到心仪的offer!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
{

try {

race(threadNum);

} catch (Exception e) {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-TVWPwB8U-1712739529157)]

[外链图片转存中…(img-54eCoQhz-1712739529158)]

[外链图片转存中…(img-7SApANeW-1712739529158)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

面试资料整理汇总

[外链图片转存中…(img-Us2xGUD8-1712739529158)]

[外链图片转存中…(img-LBJNWyrP-1712739529158)]

这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。

面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了

在这里祝大家能够拿到心仪的offer!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值