juc并发线程学习笔记(一)

JUC线程框架深度解析 — 01、JUC基础使用 一、JUC开发包简介【 java.util.concurrent开发包 】➣ 传统线程编程模型之中为防止死锁等现象的出现(wait()、notify()、   synchronized)时往往会考虑性能、公平性、资源管理等问题,这样加重了程序开发人员的负担;➣ Java5.0添加了一个新的java.util.concurrent开发包(简称JUC)。   利用此包进行的多线程编程将有效的减少竞争条... 阅读详情

本系列会更新我在学习juc时的笔记和自己的一些思想记录。如有问题欢迎联系。

并发编程

进程与线程

1.进程和线程的概念

程序是静态的,进程是动态的

进程
  • 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的
  • 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
  • 进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等)
线程
  • 一个进程之内可以分为一到多个线程。
  • 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行
  • Java 中,线程作为最小调度单位,进程作为资源分配的最小单位。 在 windows 中进程是不活动的,只是作为线程的容器
进程和线程对比
  • 进程基本上相互独立的,而线程存在于进程内,是进程的一个子集
  • 进程拥有共享的资源,如内存空间等,供其内部的线程共享
  • 进程间通信较为复杂:同一台计算机的进程通信称为 IPC(Inter-process communication)。不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
  • 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
  • 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低

2.并行和并发的概念

并发

并发能力:同一时间应对多件事情的能力。

单核 cpu 下,线程实际还是 串行执行 的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行 ,一般会将这种 线程轮流使用 CPU 的做法称为并发, concurrent。

并行

多核 cpu下,每个 核(core) 都可以调度运行线程,这时候线程可以是并行的。

引用 Rob Pike 的一段描述:

  • 并发(concurrent)是同一时间应对(dealing with)多件事情的能力
  • 并行(parallel)是同一时间动手做(doing)多件事情的能力

例子:

3.线程基本应用

应用之异步调用(案例1)

以调用方角度来讲,如果

  • 需要等待结果返回,才能继续运行就是同步
  • 不需要等待结果返回,就能继续运行就是异步

1) 设计

多线程可以让方法执行变为异步的(即不要巴巴干等着)比如说读取磁盘文件时,假设读取操作花费了 5 秒钟,如果没有线程调度机制,这 5 秒 cpu 什么都做不了,其它代码都得暂停...

//同步
@Slf4j(topic = "c.Sync")
public class Sync {

    public static void main(String[] args) {
        FileReader.read(Constants.MP4_FULL_PATH);
        log.debug("do other things ...");
    }

}

//异步
@Slf4j(topic = "c.Async")
public class Async {

    public static void main(String[] args) {
        new Thread(() -> FileReader.read(Constants.MP4_FULL_PATH)).start();
        log.debug("do other things ...");
    }

}

2) 结论

  • 比如在项目中,视频文件需要转换格式等操作比较费时,这时开一个新线程处理视频转换,避免阻塞主线程
  • tomcat 的异步 servlet 也是类似的目的,让用户线程处理耗时较长的操作,避免阻塞 tomcat 的工作线程
  • ui 程序中,开线程进行其他操作,避免阻塞 ui 线程

充分利用多核 cpu 的优势,提高运行效率。想象下面的场景,执行 3 个计算,最后将计算结果汇总。

计算 1 花费 10 ms
计算 2 花费 11 ms
计算 3 花费 9 ms
汇总需要 1 ms

  • 如果是串行执行,那么总共花费的时间是 10 + 11 + 9 + 1 = 31ms
  • 但如果是四核 cpu,各个核心分别使用线程 1 执行计算 1,线程 2 执行计算 2,线程 3 执行计算 3,那么 3 个线程是并行的,花费时间只取决于最长的那个线程运行的时间,即 11ms 最后加上汇总时间只会花费 12ms

注意
需要在多核 cpu 才能提高效率,单核仍然时是轮流执行

1) 设计

@Fork(1)
@BenchmarkMode(Mode.AverageTime)//测试模式,统计程序平均时间
@Warmup(iterations=3)//热身三次
@Measurement(iterations=5)//五轮测试取平均值
public class MyBenchmark {
    static int[] ARRAY = new int[1000_000_00];
    static {
        Arrays.fill(ARRAY, 1);
    }
    @Benchmark
    public int c() throws Exception {
        int[] array = ARRAY;
        FutureTask<Integer> t1 = new FutureTask<>(()->{
            int sum = 0;
            for(int i = 0; i < 250_000_00;i++) {
                sum += array[0+i];
            }
            return sum;
        });
        FutureTask<Integer> t2 = new FutureTask<>(()->{
            int sum = 0;
            for(int i = 0; i < 250_000_00;i++) {
                sum += array[250_000_00+i];
            }
            return sum;
        });
        FutureTask<Integer> t3 = new FutureTask<>(()->{
            int sum = 0;
            for(int i = 0; i < 250_000_00;i++) {
                sum += array[500_000_00+i];
            }
            return sum;
        });
        FutureTask<Integer> t4 = new FutureTask<>(()->{
            int sum = 0;
            for(int i = 0; i < 250_000_00;i++) {
                sum += array[750_000_00+i];
            }
            return sum;
        });
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
        new Thread(t4).start();
        return t1.get() + t2.get() + t3.get()+ t4.get();
    }
    @Benchmark
    public int d() throws Exception {
        int[] array = ARRAY;
        FutureTask<Integer> t1 = new FutureTask<>(()->{
            int sum = 0;
            for(int i = 0; i < 1000_000_00;i++) {
                sum += array[0+i];
            }
            return sum;
        });
        new Thread(t1).start();
        return t1.get();
    }
}

在单核的情况下,多线程和单线程效率基本一致,多线程会有上下文切换的耗时。

在多核的情况下,多线程比单线程就会效率翻倍。

2) 结论

单核 cpu 下,多线程不能实际提高程序运行效率,只是为了能够在不同的任务之间切换,不同线程轮流使用cpu ,不至于一个线程总占用 cpu,别的线程没法干活。

多核 cpu 可以并行跑多个线程,但能否提高程序运行效率还是要分情况的。

  • 有些任务,经过精心设计,将任务拆分,并行执行,当然可以提高程序的运行效率。但不是所有计算任务都能拆分(参考后文的【阿姆达尔定律】)
  • 也不是所有任务都需要拆分,任务的目的如果不同,谈拆分和效率没啥意义

IO 操作不占用 cpu,只是我们一般拷贝文件使用的是【阻塞 IO】,这时相当于线程虽然不用 cpu,但需要一直等待 IO 结束,没能充分利用线程。所以才有后面的【非阻塞 IO】和【异步 IO】优化

Java线程

1.创建和运行线程

创建线程对象

// 创建线程对象
Thread t = new Thread() {
 public void run() {
 // 要执行的任务
 }
};
// 启动线程,交给任务调度器,分配时间片,交给时间片去执行。
t.start();

例如:

方法一:直接使用 Thread

@Slf4j(topic = "c.Test1")
public class Test1 {

    public static void test2() {

        Thread t = new Thread(()->{ log.debug("running"); }, "t2");

        t.start();
    }
    public static void test1() {
        //匿名内部类的写法
        Thread t = new Thread(){
            @Override
            public void run() {
                log.debug("running");
            }
        };
        //创建线程的时候可以给其指定名称
        t.setName("t1");
        t.start();

    }
}

方法二:使用 Runnable 配合 Thread★

把【线程】和【任务】(要执行的代码)分开

  • Thread 代表线程
  • Runnable 可运行的任务(线程要执行的代码)

Runnable源码,如果接口中有@FunctionalInterface注解,则可以被lambda简化。如果一个接口中有多个抽象接口,是没办法用lambda简化的。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

@Slf4j(topic = "c.Test2")
public class Test2 {
    public static void main(String[] args) {
        //果接口中有@FunctionalInterface注解,则可以被lambda简化
        Runnable r = () -> {log.debug("running");};

        Thread t = new Thread(r, "t2");

        t.start();
    }
}

原理之 Thread 与 Runnable 的关系

分析 Thread 的源码,理清它与 Runnable 的关系

小结

  • 方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了
  • 用 Runnable 更容易与线程池等高级 API 配合
  • 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活

都是走的线程里的run方法。

方法三:FutureTask 配合 Thread

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

FutureTask源码分析:

实现一个RunnableFuture的接口

public class FutureTask<V> implements RunnableFuture<V> {

RunnableFuture接口又继承了Runnable和Future

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

Future里有get方法返回任务执行结果

    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

Callable源码分析

Callable可以配合FutureTask让任务执行完了,将结果传给其他线程

能抛出异常

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

实例代码:


// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
 log.debug("hello");
 return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);

输出:

19:22:27 [t3] c.ThreadStarter - hello
19:22:27 [main] c.ThreadStarter - 结果是:100

2.查看进程线程的方法

windows
  • 任务管理器可以查看进程和线程数,也可以用来杀死进程
  • tasklist 查看进程 (tasklist | findstr java)
  • taskkill 杀死进程 (taskkill /F /PID 280660)
linux
  • ps -fe 查看所有进程
  • ps -fT -p  查看某个进程(PID)的所有线程
  • kill 杀死进程
  • top 按大写 H 切换是否显示线程
  • top -H -p  查看某个进程(PID)的所有线程
Java
  • jps 命令查看所有 Java 进程
  • jstack  查看某个 Java 进程(PID)的所有线程状态
  • jconsole 来查看某个 Java 进程中线程的运行情况(图形界面)可以在window+r里直接打印

jconsole 远程监控配置

  • 需要以如下方式运行你的 java 类

java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.port=`连接端口` -Dcom.sun.management.jmxremote.ssl=是否安全连接 -
Dcom.sun.management.jmxremote.authenticate=是否认证 java类

不需要就false,ip地址和连接端口在输入后记得把`去掉

  • 修改 /etc/hosts 文件将 127.0.0.1 映射至主机名

如果要认证访问,还需要做如下步骤

  • 复制 jmxremote.password 文件
  • 修改 jmxremote.password 和 jmxremote.access 文件的权限为 600 即文件所有者可读写
  • 连接时填入 controlRole(用户名),R&D(密码)

3.线程运行的原理

栈与栈帧

ava Virtual Machine Stacks (Java 虚拟机栈)

我们都知道 JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
线程上下文切换(Thread Context Switch)

因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码

  • 线程的 cpu 时间片用完
  • 垃圾回收
  • 有更高优先级的线程需要运行
  • 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法

当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念就是程序计数器(Program Counter Register),它的作用是记住下一条 jvm 指令的执行地址,是线程私有的

  • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等
  • Context Switch 频繁发生会影响性能

4.线程

4.1start与run

调用run

public static void main(String[] args) {
 Thread t1 = new Thread("t1") {
 @Override
 public void run() {
 log.debug(Thread.currentThread().getName());
 FileReader.read(Constants.MP4_FULL_PATH);
 }
 };
 t1.run();
 log.debug("do other things ...");
}

输出:

是主线程main来调用run方法,程序仍在 main 线程运行, FileReader.read() 方法调用还是同步的

19:39:14 [main] c.TestStart - main
19:39:14 [main] c.FileReader - read [1.mp4] start ...
19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms
19:39:18 [main] c.TestStart - do other things ...

调用 start

t1.start();

输出:

19:41:30 [main] c.TestStart - do other things ...
19:41:30 [t1] c.TestStart - t1
19:41:30 [t1] c.FileReader - read [1.mp4] start ...
19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms

程序在 t1 线程运行, FileReader.read() 方法调用是异步的

小结:

  • 直接调用 run 是在主线程中执行了 run,没有启动新的线程
  • 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

4.2sleep与yield

sleep

  • 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  • 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  • 睡眠结束后的线程未必会立刻得到执行(未必能立刻获得cpu使用权)
  • 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
高并发JUC详解 多线程进阶之高并发编程 阅读详情

相关推荐

JUC 高并发编程的入门学习

课程内容概览 什么是 JUC Lock 接口 线程间通信 集合的线程安全 多线程锁 Callable 接口 JUC 三大辅助类: CountDownLatch CyclicBarrier Semaphore 读写锁: ReentrantReadWriteLock 阻塞队列 ThreadPool 线程池 Fork/Join 框架 CompletableFuture 1 什么是 JUC 1.1 JUC 简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的。JUC就是 java.u

aa35434的博客 1376

JUC并发编程

JUC并发编程 JUC简介 进程、线程的关系 Java默认有两个线程 线程的六种状态 并发、并行的关系: Lock锁 Synchronized 和 Lock的区别 8锁现象 问题一 : 在标准情况下,两个线程先打印 发短信 还是 打电话 ? 问题二 : 在发短信方法中,延迟4秒,两个线程先打印 发短信 还是 打电话? 问题三 : Phone类增加一个普通方法,线程B调用,那么两个线程先打印 发短信

识时务者的个人博客 14万+

基于《狂神说Java》JUC并发编程--学习笔记

本笔记仅做学习与复习使用,不存在刻意抄袭。给各位学友强烈推荐《遇见狂神说》他的整套Java学习路线使我获益匪浅!!!点击跳转至遇见狂神说哔哩哔哩首页如果你也是狂神的小迷弟,可以加我好友一起探讨学习。 ...

wudidahuanggua的博客 1263

一文看懂JUC多线程及高并发

本文主要介绍JUC多线程以及高并发 如有需要,可以参考 如有帮助,不忘 点赞 ❥

Cbuc丶的博客 6648

【Java之多线程】JUC常见知识点全面总结_juc 考点

大部分情况下使用就足够了锁竞争激烈的时候,使用, 搭配trylock方法可以更灵活地控制加锁的行为,而不是死等。如果需要使用公平锁, 使用信号量Semaphore一般用来表示可用资源的个数,相当于一个计数器,可类比生活中停车场牌子上面显示的停车场剩余车位数量。当有车开进去的时候, 就相当于申请一个可用资源,可用车位就 -1 (这个称为信号量的 P 操作)当有车开出来的时候, 就相当于释放一个可用资源, 可用车位就 +1 (这个称为信号量的 V 操作)

2401_84618023的博客 1223

JUC高并发编程从入门到精通(全)

目录前言 前言 在了解这部分内容的时候 先要了解java的一些基础内容 java零基础从入门到精通(全) javaSE从入门到精通(全) 所谓JUC是java.util .concurrent 工具包的简称这是一个处理线程的工具包可以实现多线程高并发的内容 了解该部分内容先了解线程与进程的相关概念 【操作系统】线程与进程的深入剖析(全) java之Thread类详细分析(全) 以及涉及到的lambda表达式函数的概念 java中lambda表达式 ......

码农研究僧的博客 1万+

【JUC基础学习笔记】

JUC基础学习笔记一、JUC概述1. JUC是什么2. 进程与线程3. 并发与并行4. sleep() 和 wait()等方法二、Lock1. Synchronized2. Lock接口与方法3. 两者异同4. Lock接口重要实现类三、线程通信 / 线程同步1. Synchronized同步块2. Lock锁四、线程安全1. 阻塞同步2. 非阻塞同步3. 非同步五、集合的线程安全1. 并发集合 ArrayList2. Vector3. Collections4. JUC.CopyOnWriteList..

sixteen_16的博客 1万+

【Java多线程】JUC之并发容器—初识并发队列BlockingQueue(一)

- 一个是以`ConcurrentLinkedQueue`为代表的高性能`非阻塞队列`, - 一个是以`BlockingQueue接口`为代表的`阻塞队列`,**无论哪种顶级接口都继承自Queue**。 - **BlockingQueue是一个接口**,它的实现类有`ArrayBlockingQueue、LinkedBlockingDeque、PriorityBlockingQueue、DelayQueue、SynchronousQueue 、LinkedTransferQueue、LinkedBlock

墩墩分墩 2322

JUC全面解析-一文带你掌握JUC

本文深入解析了Java并发工具包(JUC)的核心概念和实践应用。从线程池的创建与管理到原子操作类,再到锁机制和并发集合的使用,每个部分都通过详实的讲解帮助读者全面掌握JUC的关键知识点。我们将通过对CAS机制、AQS(抽象队列同步器)、各种同步工具(如CountDownLatch、CyclicBarrier、Semaphore)、ForkJoin框架等的讲解

weixin_67796933的博客 7828

openwrt编译及第一个安装包教程

Date: 2017.03.14 Made:SuperDeverloper Email: na1206@live.com Target: For mt7688 based board说明:本人在学习过程中走了不少弯路,希望本文档能为后来者提供便利。欢迎复制和使用本文档。本文档记录了搭建openwrt编译环境以及快速创建ipk包(openwrt上的安装程序)。本文档在实际应用中做过几次修改,以帮

SuperDevloper的博客 1万+

海康工业相机BayerRG8转BGR8实战:手把手教你用OpenCV实现高效图像转换

本文详细解析了海康工业相机BayerRG8格式到BGR8格式的高效转换实战。针对工业视觉项目中高帧率、大分辨率场景下的性能瓶颈,文章对比了海康SDK原生方案与OpenCV多种转换方法的优劣,并提供了从基础实现到高级优化(如多线程流水线、内存管理、SIMD指令集应用)的完整代码示例与性能调优策略,帮助开发者构建稳定、高效的图像处理系统。

weixin_29237635的博客 522

【并发编程】JUC并发编程(彻底搞懂JUC)

JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称,其结构如下:这个包下都是Java处理线程相关的类,自jdk1.5后出现。目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题!JUC主要是指JDK8中java.util.concurrent里提供的一系列线程并发工具,但是线程并发的问题远不止几个工具这么简单。要学习工具使用,更要能深入理解工具的原理以及处理线程并发问题的思路。

DreamSun的博客 7611

一文搞懂【Linux 搭建 Dread Hunger 服务器】附本体及Docker部署集群方案

看直播发现了五花八门的开服器和版本,一时兴起按官方文档进行了搭建尝试,所以我的版本基于官方Stream2024.01.10更新的版本,也就是停服时的玩法,应该可以根据mod和补丁魔改成更那些开服器一样的版本,本文不做谈论,注重服务器搭建,毕竟8个人不可能在一个局域网里乱象:首先,我看了大量教程视频,一类是开服器的推广,另一类自建的基本采用Windows搭建,我觉得最离谱的是大部分教程都会教你买一台远程Windows虚拟机???

LHmine的博客 3983

多线程--JUC并发编程

多线程、并发相关知识点

weixin_45690338的博客 2095

Fluent后台计算中Journal文件的自动化编写与优化实践

本文深入探讨了Fluent在Linux/Unix环境下进行后台计算时,Journal文件的自动化编写与优化实践。Journal文件作为Fluent后台计算的“灵魂”,是实现仿真流程自动化、保证计算可重复性与准确性的关键。文章从基础脚本骨架搭建、命令简写技巧,到进阶的参数化研究与批量计算实现,提供了详实的实战指南,帮助工程师大幅提升仿真效率。

postgres8guard的博客 754

ai数字人系统部署

这段代码实现了基本的语音交互闭环,用户通过语音输入问题,数字人识别语音后进行自然语言理解并生成回复,再将回复转换为语音输出。但实际应用中的 AI 数字人系统更为复杂,如形象渲染需专业图形引擎(如 Unity、Unreal Engine),自然语言处理也会涉及更复杂的模型微调及多轮对话管理等。一个完整的 AI 数字人系统涵盖形象生成、自然语言处理、动作控制等多个复杂功能,下面为你提供一个 Python 示例,整合多个库来实现数字人基础功能,包括语音交互、简单的自然语言理解以及通过虚拟形象展示对话。

weixin_ggwwsscc的博客 368

JUC系列——JUC入门及多线程并发

JUC是什么? 多线程 多线程并发 多并发,高可用

yezhijing的专栏 2063

密码学系列3-Elgamal加密及其IND-CPA安全性证明

但这没有任何影响,敌手本身就只能知道公钥,他并没有能力知道挑战者是否知道对应的私钥。所以上述整个游戏就是一个模拟实验,敌手无法区分挑战者运行的是这个模拟实验,还是真正的按照第一节的算法构造的实验(挑战者知道私钥…为什么合起来的时候有1/2:因为T既可能是随机的也可能是g^{ab},这两种情况概率为1/2。能够攻破Elgamal加密方案,那么挑战者利用敌手的能力构建下面游戏,来求解困难性问题DDH。就是挑战者选的随机数,虽然挑战者自己也不知道。),否则挑战者输出0,作为DDH的回答。

qq_41359358的博客 1249

深入解析Java多线程与并发编程(五)(JUC显示锁、AQS抽象同步器以及JUC高并发容器)

本文介绍了JUC显式锁、AQS抽象同步器以及JUC高并发容器的基本概念。JUC显式锁是一种灵活的Java实现锁,支持多种锁操作,如可轮询、定时、可中断等。显式锁的核心接口是Lock,其主要实现类为ReentrantLock,具有可重入、独占等特性。显式锁可分为可重入锁、不可重入锁、悲观锁、乐观锁、公平锁、非公平锁、可中断锁、不可中断锁、共享锁和独占锁等类型。悲观锁适用于写多读少场景,而乐观锁适用于读多写少场景。公平锁保障线程按顺序获取锁,非公平锁则不保证。可中断锁允许在抢占过程中中断,而不可中断锁则不允许。

wxchyy的博客 1415

uniapp - 微信支付报错 {“errMsg“:“requestPayment:fail:[payment微信:-1]General errors“} 详细解决办法,uniApp使用微信支付时报错

uniapp,微信支付报错,uniapp微信小程序 H5网页 安卓苹果ios真机调试时报错,uniapp真机测试微信支付报错如何解决,调用微信支付出现报错{"errMsg":"requestPayment:fail:[payment微信:-1]General errors"},微信支付提示错误,uniapp进行微信支付时报错怎么解决,如何解决微信支付报错,uniapp微信支付报错fail,uni-app真机测试ios上报错,uniapp真机测试安卓手机第一次支付成功第二次就报错了,uniapp微信支付调用第

✅ 精选推荐文章 4133

使用 Simulink 进行电力电子系统的大信号模型仿真

电力电子系统(Power Electronics System)包括各种功率转换器(如 DC-DC 转换器、逆变器等)。这些设备中的关键组件(如 MOSFET、IGBT、电容器、电感器等)不仅影响系统的性能,还直接关系到系统的稳定性、效率和可靠性。因此,在设计阶段进行详细的建模和仿真至关重要。大信号模型仿真的目的是通过模拟系统在非线性条件下的真实行为,评估其瞬态响应、稳态性能以及对不同负载和输入电压变化的响应。通过本教程,我们介绍了如何使用 Simulink 进行电力电子系统的大信号模型仿真。背景介绍。

xiaoheshang_123的博客 303

【java 高并发编程之JUC】2w字带你JUC从入门到精通

wait()是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(Object)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 WAITING 状态,自然是要操作对应的对象(Object)而非当前的线程(Thread为什么sleep()方法定义在Thread中?因为sleep()是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。java JUC 中 Object里wait()、notify() 实现原理及实战讲解。

LoveSummer 6万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

周阳老师JUC并发编程

周阳老师JUC并发编程

qq_44300280的博客 7143

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JUC学习笔记(一)

文章目录一、进程与线程1.1 进程与线程1)进程2)线程3)二者对比1.2 并行与并发注意二、Java线程2.1 创建和运行线程1)直接使用 Thread2)使用 Runnable 配合 Thread3)FutureTask 配合 Thread2.2 查看进程线程的方法1)windows2)linux3)java2.3 原理之线程运行栈与栈帧线程上下文切换2.4 常见方法2.5 start 与 run2.6 sleep 与 yieldsleepyield线程优先级2.7 join 方法详解为什么需要 jo

zhou22的博客 2167

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: Spring系列学习笔记->Spring篇(一)
下一篇: 项目中spring security与jwt
happystudy_neu
博客等级 码龄4年 1140粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值