前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java多线程与并发-原理

Java多线程与并发-原理

作者头像
瑞新
发布2020-07-07 20:49:12
6440
发布2020-07-07 20:49:12
举报

synchronized

堆是线程间共享的,要合理的给一个对象上锁。

线程安全主要诱因

在这里插入图片描述
在这里插入图片描述

互斥锁特性

在这里插入图片描述
在这里插入图片描述

获取对象锁

在这里插入图片描述
在这里插入图片描述

同对象,异步

在这里插入图片描述
在这里插入图片描述

同对象,同步代码块

在这里插入图片描述
在这里插入图片描述

同对象,非静态同步方法

在这里插入图片描述
在这里插入图片描述

同对象,同步代码块 对比 非静态同步方法

在这里插入图片描述
在这里插入图片描述

不同对象,同步代码块 对比 非静态同步方法

在这里插入图片描述
在这里插入图片描述

获取类锁

类锁通过对象锁实现的

在这里插入图片描述
在这里插入图片描述

和对象锁的变动-代码块和静态方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

同对象,类锁 对比 对象锁

因为类锁是对象锁实现的 同对象,传入了同种对象实例

在这里插入图片描述
在这里插入图片描述

不同对象,类锁 对比 对象锁

互不干扰,因为锁两个对象锁

在这里插入图片描述
在这里插入图片描述

同对象,类锁 对比 对象锁

在这里插入图片描述
在这里插入图片描述

代码实现

SyncDemo

package thread;

public class SyncDemo {
    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        // 异步
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");

        // 对象锁
        // 同步代码块
        Thread B_thread1 = new Thread(syncThread, "B_thread1");
        Thread B_thread2 = new Thread(syncThread, "B_thread2");
        // 同步非静态方法
        Thread C_thread1 = new Thread(syncThread, "C_thread1");
        Thread C_thread2 = new Thread(syncThread, "C_thread2");

        // 类锁
        // 同步代码块
        Thread D_thread1 = new Thread(syncThread, "D_thread1");
        Thread D_thread2 = new Thread(syncThread, "D_thread2");
        // 同步静态方法
        Thread E_thread1 = new Thread(syncThread, "E_thread1");
        Thread E_thread2 = new Thread(syncThread, "E_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
        D_thread1.start();
        D_thread2.start();
        E_thread1.start();
        E_thread2.start();
    }
}

SyncThread

package thread;

import java.text.SimpleDateFormat;
import java.util.Date;

public class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            syncObjectBlock1();
        } else if (threadName.startsWith("C")) {
            syncObjectMethod1();
        } else if (threadName.startsWith("D")) {
            syncClassBlock1();
        } else if (threadName.startsWith("E")) {
            syncClassMethod1();
        }

    }

    /**
     * 异步方法
     */
    private void async() {
        try {
            System.out.println(Thread.currentThread().getName() + "_Async_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_Async_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法中有 synchronized(this|object) {} 同步代码块
     */
    private void syncObjectBlock1() {
        System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (this) {
            try {
                System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * synchronized 修饰非静态方法
     */
    private synchronized void syncObjectMethod1() {
        System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void syncClassBlock1() {
        System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (SyncThread.class) {
            try {
                System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized static void syncClassMethod1() {
        System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

总结

在这里插入图片描述
在这里插入图片描述

synchronized底层实现原理

实现synchronized基础

Java对象头 Monitor

对象在内存中的布局

对象头 实例数据 对齐填充

对象头结构

synchronized的锁对象是存在对象头里的 MarkWord存储对象运行时数据。 是实现 轻量级锁 和 偏向锁(Java6后新增加的)的关键 由于对象头信息是与对象自身定义没有关系的额外存储成本,因此考虑到JVM的效率,MarkWord 被设计为一个非固定的数据结构,以便存储更多的有效数据,根据对象状态复用自身的存储空间 重量级锁:synchronized对象锁,指向的指针是Monitor的起始地址。每个对象和Monitor存在关联,对象与Monitor之间有多种实现形式 如:对象可以和Monitor同时创建或销毁 或 单线程试图获得对象锁时,自动生成。 Monitor被某个线程持有后变为锁定状态 在Java虚拟机及hospot虚拟机,Monitor是由hospotMonitor实现的(源码C++实现的)

在这里插入图片描述
在这里插入图片描述

MonitorJava娘胎创建的锁 管程 或 监视器锁(描述为 同步工具,或同步机制,通常被描述为同步对象)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Monitor锁的竞争、获取与释放

Monitor存在每个对象的对象头中,synchronized通过这种方式获取锁 ,这也是Java任意对象可以作为锁的原因

在这里插入图片描述
在这里插入图片描述

字节码层面分析

在这里插入图片描述
在这里插入图片描述

看.class里边的文件 javap -verbose

什么是重入-知识补充

重入请求将会成功,synchronize是Java原子性的内部锁机制是可重入的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

同步块-字节码分析

线程通过计数器判断,本次是否应该先阻塞

在这里插入图片描述
在这里插入图片描述

同步方法体-字节码分析

没有monitorenter、monitorexit、指令少。 方法体是隐式的,即无需通过字节码控制 正常完成或非正常完成,都释放monitor 如果内有异常,内部无法处理,会抛到外部直到释放

在这里插入图片描述
在这里插入图片描述

为什么会对synchronized嗤之以鼻

重量级锁,监视器锁Monitor运行在底层操作系统。切换线程,时间长。效率低

在这里插入图片描述
在这里插入图片描述

Java6后,在JVM层面做了大量优化

自适应自旋 锁消除 锁粗化 轻量级锁 偏向锁 …… 为了在线程间更高效的共享数据,解决竞争问题,高效程序执行效率

自旋锁

等一会,不放弃cpu,忙循环等待持有锁的线程释放锁 不像sleep一样放弃cpu的执行时间 Java4被引入默认关闭,但Java6才启用 本质上与阻塞并不相通,考虑其对多处理器 的要求

在这里插入图片描述
在这里插入图片描述

自适应自旋锁

每次线程需要等待的时间还有次数是不固定的 因此PreBlockSpin无法设计的很合理 JVM对锁的预测越来越精准,JVM越来越聪明

在这里插入图片描述
在这里插入图片描述

锁消除

在这里插入图片描述
在这里插入图片描述

StringBuffer虽然是线程安全的,但操作本地变量(不是共享的)JVM消除内部锁,避免资源浪费

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

锁粗化

在这里插入图片描述
在这里插入图片描述

synchronized的四种状态

随竞争情况逐渐升级 其实锁降级会发生:当JVM进入前面的安全点,会检测是否有闲置的Monitor ,然后试图降级

在这里插入图片描述
在这里插入图片描述

偏向锁

CAS无锁算法

在这里插入图片描述
在这里插入图片描述

轻量级锁

在这里插入图片描述
在这里插入图片描述

加锁过程

初始-无锁01 拷贝-(CAS更新)双向指向-成功轻量级00 失败-判断markword是否指向栈帧 ?有则说明当前线程拥有这个对象的锁,进入同步块:没有则说明多个线程竞争锁,轻量级锁->重量级锁10 变成重量级锁时候,其他线程会阻塞,自旋会防止阻塞

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解锁

在这里插入图片描述
在这里插入图片描述

锁的内存语义-补充知识-解锁轻量级怎么就成功了?

在这里插入图片描述
在这里插入图片描述

偏向锁、轻量级锁、重量级锁 汇总

在这里插入图片描述
在这里插入图片描述

synchronized和ReentrantLock

ReentrantLock的区别

Java5之前只有synchronized,从5之后有了ReentrantLock(再入锁)

在这里插入图片描述
在这里插入图片描述

源码ReentrantLock-AQS

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AQS

state数组成员表存状态 队列 CAS基础 acquire获取资源独占权 release释放对某个资源的独占

ReentrantLock公平性设置

理解

公平性Java中一般用的不多,synchronized一般也不会引起饥饿, 除非必须要用公平性,因为开启公平性会增加额外的开销,导致程序吞吐量下降

在这里插入图片描述
在这里插入图片描述

公平效果图

在这里插入图片描述
在这里插入图片描述

不公平效果图

在这里插入图片描述
在这里插入图片描述

ReentrantLock将锁对象化

在这里插入图片描述
在这里插入图片描述

其他对象化

在这里插入图片描述
在这里插入图片描述

追源码

ArrayBlockingQueue 数组实现、线程安全的(ReentrantLock互斥锁保护资源)、有界的(数组长度)、阻塞队列 ArrayBlockingQueue与Condition是组合的关系 Condition依附于ArrayBlockingQueue存在

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

队列为空等待有新的消息加入再返回 条件判断通知等待线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

来自AQS框架

在这里插入图片描述
在这里插入图片描述

总结synchronized和ReentrantLock区别

区别

在这里插入图片描述
在这里插入图片描述

追源码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

unsafe 类似后门工具 可以在任意内存位置读写数据,对普通用户操作比较危险 支持一些CAS操作

在这里插入图片描述
在这里插入图片描述

jmm的内存可见性

Java内存模型中的happens-before

Jmm

工作内存是每个线程的私有区域

在这里插入图片描述
在这里插入图片描述

Jmm主内存

在这里插入图片描述
在这里插入图片描述

Jmm工作内存

在这里插入图片描述
在这里插入图片描述

Jmm和Java比较

主内存:好似,堆、方法区 工作内存:

在这里插入图片描述
在这里插入图片描述

主内存和工作内存-数据存储类型-操作方式 归纳

在这里插入图片描述
在这里插入图片描述

Jmm如何解决可见性

忽略硬件部分,简单理解为从内存读取到缓存取处理,后存入内存。 线程共享变量,一致性问题。由于多线程,很有可能第二条线程处理的数据是前一条线程处理前的旧状态,为此引入了复杂的数据依赖性。 重排序要尊重数据依赖性的要求,否则就打破了数据的正确性。

在这里插入图片描述
在这里插入图片描述

指令重排序的满足条件

为了提高性能。处理器,编译器常常对指令重排序(不能随意重排序) JMM一般通过禁止某些指令的重排序,来保障内存可见性,也就是实现了happens-before规则。

在这里插入图片描述
在这里插入图片描述

happens-before原则

在这里插入图片描述
在这里插入图片描述

使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回。这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行。

Thread Join 方法。在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上述不满足线程安全,需要通过以下两条变成happens-before 修复代码:(使满足锁 或 volatile变量规则)

在这里插入图片描述
在这里插入图片描述

volatile内存语义-补充知识

volatile保证写的可见性 但是多线程的运算 操作并不保证安全性

在这里插入图片描述
在这里插入图片描述

synchronized控制直接反馈给主存

在这里插入图片描述
在这里插入图片描述

利用立即可见的原子性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

volatile如何立即可见

通过(对主内存) 写 读 的方式,达到立即可见的效果

在这里插入图片描述
在这里插入图片描述

volatile如何禁止重排优化

内存屏障 cpu指令 因为编译器、处理器,都会影响指令的重排优化。 如果插入 内存屏障 ,则告诉编译器、或cpu,任何指令都不能与 内存屏障 重排序,不能打乱他们的顺序

在这里插入图片描述
在这里插入图片描述

线程安全的单例实现算法-单例双重检测

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

volatile和synchronize的区别

在这里插入图片描述
在这里插入图片描述

CAS

CAS线程安全,乐观锁

cynchronize属于悲观锁,始终假定会出现并发冲突,因此屏蔽一切可能违反数据完整性的操作 乐观锁则,假设不会发生并发冲突,因此只在提交操作时检查是否违反数据完整性,如果提交失败,则会重试,乐观锁最常见的是CAS CAS上层感觉无锁,其实底层还是有加锁行为的。操作失败,自己决定,因此不会被阻塞挂起

在这里插入图片描述
在这里插入图片描述

CAS思想

V和A相比较,如果一致,会将该位置的值更新为新值。否则不做任何操作 V是主内存的值

在这里插入图片描述
在这里插入图片描述

场景举例,追源码

场景举例: 当要更新一个共享变量的值。 会取该变量的值到A,然后经过计算,得到新值B 需要更新共享变量的值的时候,调用CAS方法去更新共享变量的值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

volatile保证线程可见性,同时不允许线程对其重排序,但是不能保证下面三个指令原子执行,在多线程并发无法做到线程安全得到正确结果 改进方案(可行,但近一步提升性能,不用synchronized的悲观锁)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

深入到jvm指令集源码会发现,不同的体系架构指令集不同

在这里插入图片描述
在这里插入图片描述

CAS多数情况下对开发者来说是透明的

多数情况下,开发者不需要直接利用CAS代码实现线程安全容器 更多的是使用并发包间接的享受在扩展性的好处

在这里插入图片描述
在这里插入图片描述

CAS虽然高效的解决了原子操作问题 循环长 比如上方:getAddInt,如果失败一直while尝试 CAS可保障一个共享变量 原子性,多个共享变量就得用锁来保障原子性 ABA:如果V初次读取的是A,(这期间可能被改变过B)并在准备赋值的时候仍然为A。可能被误认为重来没有被改变过 为解决ABA问题:JUC带有标记的原子引用类, 通过控制变量值的版本来解决ABA的问题 改为传统的互斥同步,可能比原子的更高效 设计程序前,想好ABA问题是否影响程序的并发性

在这里插入图片描述
在这里插入图片描述

Java线程池

利用Executors创建五种不同线程池满足不同场景需求

服务端处理并发请求多,但每个线程执行的时间很短,就会频繁的创建销毁请求,会大大降低系统效率。可能出现创建销毁的时间,要比处理用户请求的时间和资源更多,那么有没有一种方法重复利用线程去完成新任务呢?

在这里插入图片描述
在这里插入图片描述

Fork/Join框架

在这里插入图片描述
在这里插入图片描述

为啥要用线程池

通过重复利用已经创建的线程,降低(线程频繁创建、销毁)资源消耗 使用线程池可统一进行分配、调优、监控

追源码

1

在这里插入图片描述
在这里插入图片描述

2

在这里插入图片描述
在这里插入图片描述

3

在这里插入图片描述
在这里插入图片描述

深入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

后面又是Excecutor

Executor

以上都是属于此框架的体系的类或接口 根据一组执行策略调度异步任务的框架,目的是将任务提交,和任务如何运行分离开的机制 Executors提供尽量简化操作的工厂方法

在这里插入图片描述
在这里插入图片描述

JUC的三个Executor接口

三接口

在这里插入图片描述
在这里插入图片描述

Executor

对与不同execute实现可能情况 创建新线程 传入已有线程 根据线程池的容量 阻塞队列的容量,来决定传入的线程是否放入阻塞队列中,或者拒绝接受阻塞的线程 执行方法 直接将线程给execute方法去执行

在这里插入图片描述
在这里插入图片描述

ExecutorService实现更多管理生命周期的方法

在这里插入图片描述
在这里插入图片描述

非5场景的,自定义创建线程池场景-ThreadPoolExecutor来创建

简单了解ThreadPoolExecutor来创建

大多数场景使用Executor提供的5种线程池就够,但其他场景还是要自己用ThreadPoolExecutor来创建 分析线程池的设计与实现: 队列存储用户的提交,是一个工作队列 队列接到客,就排队提交给内部的线程池(工作线程的集合),该集合需要管理线程的创建和销毁 当线程池压力较大,会创建新的线程,当任务量变小,线程池会闲置一段时间,结束线程 。线程池的工作线程,被抽象为静态内部类worker,TreadPool实际上维护的就是一组worker对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

worker追源码,分析组成

在这里插入图片描述
在这里插入图片描述

firstTask来保存传入的任务 thread调用构造方法函数时,通过ThreadFactory来创建的线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

因为worker实现了runable方法 调用run方法去执行里面的逻辑

在这里插入图片描述
在这里插入图片描述

比如任务提交被拒绝,线程池已经处于shutdown的状态,此时新来的任务需要有处理机制来处理

在这里插入图片描述
在这里插入图片描述

组成成分体现在-构造函数

在这里插入图片描述
在这里插入图片描述

以及最后补充的饱和策略

在这里插入图片描述
在这里插入图片描述

长期驻留线程数,对不同线程池可能会有很大区别

在这里插入图片描述
在这里插入图片描述

比如

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

比如固定

在这里插入图片描述
在这里插入图片描述

或动态

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

线程提交时,线程池的线程数量大于corePoolSize,把该任务封装成一个worker对象放入等待队列。 由于存在许多种等待队列,每种不同队列有不同的排队机制。可以自行体会感受线程池带来的灵活

在这里插入图片描述
在这里插入图片描述

线程池维护线程,所允许的空闲时间。 当线程池里的线程数量大于corePoolSize,如果这时没有新的任务提交,核心线程不会立即被销毁,直到等待时间超过keepAliveTime,才会被销毁

在这里插入图片描述
在这里插入图片描述

会使新创建的线程具有相同的优先级,并且是非守护线程,同时也设置了线程名称

在这里插入图片描述
在这里插入图片描述

如果阻塞队列满了,并且没有空闲的线程,如果继续提交任务,就需要采取一种策略

组成成分流程-简单模拟

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

细节-一种优雅的传值方式

线程池和线程一样也会有生命周期,生命周期通过状态值来表示的。 线程池用来管理线程,因此对线程的数量一定是了如指掌的,有存储当前有效线程数 ThreadPoolExecutor将状态值和有效线程数合二为一,存储到了ctl ctl高三位存状态值,低29位保存有效线程数

在这里插入图片描述
在这里插入图片描述

对ctl进行优雅计算的(用的与或非,执行起来相当高效) 获取运行状态 获取活动线程数 ctl获取两者

在这里插入图片描述
在这里插入图片描述

线程池的五种状态

TIDYING workercount有效线程数为零,正在做打扫操作 TERMINATED什么也不做只作为一个标识

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程池大小如何选定

没有固定,看工作经验

在这里插入图片描述
在这里插入图片描述

推荐书籍

Java并发编程实战

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • synchronized
    • 线程安全主要诱因
      • 互斥锁特性
        • 获取对象锁
          • 同对象,异步
          • 同对象,同步代码块
          • 同对象,非静态同步方法
          • 同对象,同步代码块 对比 非静态同步方法
          • 不同对象,同步代码块 对比 非静态同步方法
        • 获取类锁
          • 和对象锁的变动-代码块和静态方法
            • 同对象,类锁 对比 对象锁
            • 不同对象,类锁 对比 对象锁
          • 同对象,类锁 对比 对象锁
            • 代码实现
              • SyncDemo
              • SyncThread
            • 总结
            • synchronized底层实现原理
              • 实现synchronized基础
                • 对象在内存中的布局
                  • 对象头结构
                  • Monitor锁的竞争、获取与释放
                  • 字节码层面分析
                  • 什么是重入-知识补充
                  • 同步块-字节码分析
                  • 同步方法体-字节码分析
                • 为什么会对synchronized嗤之以鼻
                  • Java6后,在JVM层面做了大量优化
                  • 自旋锁
                  • 自适应自旋锁
                  • 锁消除
                  • 锁粗化
                • synchronized的四种状态
                  • 偏向锁
                  • 轻量级锁
                  • 加锁过程
                  • 解锁
                  • 锁的内存语义-补充知识-解锁轻量级怎么就成功了?
                  • 偏向锁、轻量级锁、重量级锁 汇总
              • synchronized和ReentrantLock
                • ReentrantLock的区别
                  • 源码ReentrantLock-AQS
                    • ReentrantLock公平性设置
                      • 理解
                      • 公平效果图
                      • 不公平效果图
                    • ReentrantLock将锁对象化
                      • 其他对象化
                        • 追源码
                      • 总结synchronized和ReentrantLock区别
                        • 区别
                        • 追源码分析
                    • jmm的内存可见性
                      • Java内存模型中的happens-before
                        • Jmm
                          • Jmm主内存
                          • Jmm工作内存
                        • Jmm和Java比较
                          • 主内存和工作内存-数据存储类型-操作方式 归纳
                            • Jmm如何解决可见性
                              • 指令重排序的满足条件
                              • happens-before原则
                              • volatile内存语义-补充知识
                              • volatile如何立即可见
                              • volatile如何禁止重排优化
                              • 线程安全的单例实现算法-单例双重检测
                            • volatile和synchronize的区别
                            • CAS
                              • CAS线程安全,乐观锁
                                • CAS思想
                                  • 场景举例,追源码
                                    • CAS多数情况下对开发者来说是透明的
                                    • Java线程池
                                      • 利用Executors创建五种不同线程池满足不同场景需求
                                        • Fork/Join框架
                                          • 为啥要用线程池
                                            • 追源码
                                              • Executor
                                                • JUC的三个Executor接口
                                                  • 三接口
                                                  • Executor
                                                  • ExecutorService实现更多管理生命周期的方法
                                                • 非5场景的,自定义创建线程池场景-ThreadPoolExecutor来创建
                                                  • 简单了解ThreadPoolExecutor来创建
                                                  • worker追源码,分析组成
                                                  • 组成成分体现在-构造函数
                                                  • 组成成分流程-简单模拟
                                                  • 细节-一种优雅的传值方式
                                                • 线程池的五种状态
                                                  • 线程池大小如何选定
                                                  • 推荐书籍
                                                  相关产品与服务
                                                  容器服务
                                                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                  领券
                                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档