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

article/2025/9/19 18:42:16

文章目录

  • 前言
  • 一、JUC简介
    • 1、出自哪位大神之手?
    • 2、JUC是什么?
  • 二、JUC主要解决什么问题?
    • 1、进程 、线程
    • 2、并发、并行
    • 3、JAVA创建线程的方式(模拟三种线程实现方式)
      • 1)继承Thread类(线程的初级用法)
      • 2)实现Runnable 接口(线程的初级用法)
      • 3)内部类方式(线程的中级用法)
      • 4) 使用lamada 表达式实现(高级用法,也是企业中最常使用的方法)
  • 总结


前言

随着JAVA程序员越来越卷,导致现在他们需要不断的学习更深的知识来达到卷的资本。本期系统教程主要介绍JUC,这一章就让我们从头来认识一下它吧,做为一名资深的JAVA程序员,你必需知道什么是JUC,JUC是用来做什么的,怎么用。这也是大厂面试必问技术之一。


一、JUC简介

1、出自哪位大神之手?

  • JUC 是美国的一位大学教师 Doug Lea (道格·利)设计并开发出来的。
  • Doug Lea 服务于纽约州立大学Oswego分校计算机学系的教师。
  • Doug Lea 是 JCP(JAVA社区项目)中的一员。
  • 让我们瞻仰一下大神的容貌,多向大神学习。
    在这里插入图片描述

2、JUC是什么?

  • JUC是 JDK中java.util.concurrent 包的简称(中文简称:并发工具包),它包含三个包:
    • java.util.concurrent
    • java.util.concurrent.atomic
    • java.util.concurrent.locks
  • 2004年10月发布的JDK1.5新增用来编写并发相关的基础api。
  • 目前JUC泛指JAVA多线程开发技术。

二、JUC主要解决什么问题?

JUC 主要解决的问题是:在高内聚低耦合的前提下,线程如何操作 资源类可以达到高并发高可用的效果?

先来学习一下几个基本概念

1、进程 、线程

  • 进程:
    • 操作系统可调配的最小单元。
    • 有自己独立的空间。
    • 比如:系统中运行的QQ、CF、王者,它们都是独立的进程。
  • 线程:
    • 线程是进程可中可调配的最小单元。
    • 一个进程内可以包含多个线程。
    • 如:360卫士里包含了许多功能,杀毒、下载软件等,它们是一个进程内不同的线程。

2、并发、并行

  • 并发:
    • 同一个功能被同时调用。
    • 同一段程序被同时调用。
  • 并行:
    • 不同的功能被同时调用。
    • 不同的程序被同时调用。

JUC就是解决多线程执行中遇到的问题,所以我们再来看一下JAVA里是怎么创建线程和操作线程的

3、JAVA创建线程的方式(模拟三种线程实现方式)

模拟一个多线程的需求:火车售票员 A、B、C三个人同时出售一列火车的10张票,售完为止。

1)继承Thread类(线程的初级用法)

使用JUC中的Lock实现不现线程对同一资源的操作
售票员类:

package com.juc.study;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 火车售票员*/
public class TrainConductor extends Thread {public TrainConductor() {}public TrainConductor(String name) {super(name);}/*** 售票*/public void saleTickets() {// JUC中的锁,是轻量级的锁,实现类是可重入锁,// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。Lock lock = new ReentrantLock();lock.lock();try {if(Ticket.nums > 0) {System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}@Overridepublic void run() {for(int i = 70; i > 0; i--) {saleTickets();}}
}

火车票类:

package com.juc.study;public class Ticket {public static int nums = 10;}

执行类:

import com.juc.study.Ticket;
import com.juc.study.TrainConductor;public class TestJUC {public static void main(String[] args) {// 新建三个售票员TrainConductor trainConductorA = new TrainConductor("A");TrainConductor trainConductorB = new TrainConductor("B");TrainConductor trainConductorC = new TrainConductor("C");// 开始售票trainConductorA.start();trainConductorB.start();trainConductorC.start();}}

执行结果:

A	 卖出第:9张,	 还剩下:8
C	 卖出第:8张,	 还剩下:7
B	 卖出第:10张,	 还剩下:8
C	 卖出第:6张,	 还剩下:5
C	 卖出第:4张,	 还剩下:3
A	 卖出第:7张,	 还剩下:6
C	 卖出第:3张,	 还剩下:2
C	 卖出第:1张,	 还剩下:0
A	 卖出第:2张,	 还剩下:1
B	 卖出第:5张,	 还剩下:4

2)实现Runnable 接口(线程的初级用法)

与继承Thead类的写法有点区别,大家注意观察
售票员类:

package com.juc.study;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 售票员类*/
public class TrainConductorRunnable implements Runnable{/*** 售票*/public void saleTickets() {// JUC中的锁,是轻量级的锁,实现类是可重入锁,// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。Lock lock = new ReentrantLock();lock.lock();try {if(Ticket.nums > 0) {System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}@Overridepublic void run() {for(int i = 70; i > 0; i--) {saleTickets();}}
}

火车票类(无变化):

package com.juc.study;public class Ticket {public static int nums = 10;}

执行类:

import com.juc.study.Ticket;
import com.juc.study.TrainConductor;
import com.juc.study.TrainConductorRunnable;public class TestJUC {public static void main(String[] args) {// 新建三个售票员TrainConductorRunnable trainConductorA = new TrainConductorRunnable();TrainConductorRunnable trainConductorB = new TrainConductorRunnable();TrainConductorRunnable trainConductorC = new TrainConductorRunnable();// 新建三个线程Thread t1 = new Thread(trainConductorA, "A");Thread t2 = new Thread(trainConductorB, "B");Thread t3 = new Thread(trainConductorC, "C");// 开始售票t1.start();t2.start();t3.start();}}

执行结果:

A	 卖出第:9张,	 还剩下:7
C	 卖出第:8张,	 还剩下:7
A	 卖出第:7张,	 还剩下:6
B	 卖出第:10张,	 还剩下:7
A	 卖出第:5张,	 还剩下:4
C	 卖出第:6张,	 还剩下:5
A	 卖出第:3张,	 还剩下:2
B	 卖出第:4张,	 还剩下:3
A	 卖出第:1张,	 还剩下:0
C	 卖出第:2张,	 还剩下:1

3)内部类方式(线程的中级用法)

使用内部类实现是不需要继承Thread类或实现Runnable接口,大家仔细看

火车售票员类:

package com.juc.study;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 火车售票员(采用内部类的形式实现)*/
public class TrainConductorInner {/*** 售票*/public void saleTickets() {// JUC中的锁,是轻量级的锁,实现类是可重入锁,// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。Lock lock = new ReentrantLock();lock.lock();try {if(Ticket.nums > 0) {System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}}

火车票类(无变化):

package com.juc.study;public class Ticket {public static int nums = 10;}

执行类:

import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;public class TestJUC {public static void main(String[] args) {Thread t1 = new Thread("A") {@Overridepublic void run() {for(int i = 70; i > 0; i--) {TrainConductorInner a = new TrainConductorInner();a.saleTickets();}}};t1.start();Thread t2 = new Thread("B") {@Overridepublic void run() {for(int i = 70; i > 0; i--) {TrainConductorInner b = new TrainConductorInner();b.saleTickets();}}};t2.start();Thread t3 = new Thread("C") {@Overridepublic void run() {for(int i = 70; i > 0; i--) {TrainConductorInner c = new TrainConductorInner();c.saleTickets();}}};t3.start();}}

4) 使用lamada 表达式实现(高级用法,也是企业中最常使用的方法)

lamada表达式写完之后有点长,如果看不懂可以给它格式化一下

火车售票员类(仍然使用内部类,没变化):

package com.juc.study;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 火车售票员(采用内部类的形式实现)*/
public class TrainConductorInner {/*** 售票*/public void saleTickets() {// JUC中的锁,是轻量级的锁,实现类是可重入锁,// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。Lock lock = new ReentrantLock();lock.lock();try {if(Ticket.nums > 0) {System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}}

火车票类(没变化):

package com.juc.study;public class Ticket {public static int nums = 10;}

执行类(这里使用lamada表达式):

import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;public class TestJUC {public static void main(String[] args) {new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner a = new TrainConductorInner(); a.saleTickets();}}, "A").start();new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner b = new TrainConductorInner(); b.saleTickets();}}, "B").start();new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner c = new TrainConductorInner(); c.saleTickets();}}, "C").start();}}

总结

最重要的一句话:在高内聚低耦合的前提下,线程操作资源类达到高并发高可用的效果就是JUC的任务。
JUC的入门就到这里,到这里大家应该会对JUC有点感觉了,感觉是不是挺好玩的,后面的章节更精彩,敬请期待。。。。。。


http://chatgpt.dhexx.cn/article/cpa1N7ly.shtml

相关文章

Java进阶|JUC系列(持续更新)

文章目录 1、什么是J.U.C2、进程、线程、协程2.1 简介2.2 线程有几个状态2.3 wait和sleep的区别 3、Lock锁(重点)3.1 简介3.2 lock锁和synchronized有什么区别 4、生产者和消费者问题4.1 简介4.2 使用synchronized实现的demo4.3使用Lock实现的demo 5、锁的是谁问题1、两个线程访…

莱布尼茨公式C语言编程,高等数学——手撕牛顿莱布尼茨公式

本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是高等数学专题的第13篇文章,我们来看看定积分究竟应该怎么计算。 定积分的实际意义 通过之前的文章,我们基本上熟悉了定积分这个概念和它的一些简单性质&#x…

[计算机数值分析]牛顿插值公式

Spring-_-Bear 的 CSDN 博客导航 埃特金算法虽然具有承袭性,但其算式是递推型的,不便于进行理论上的分析。所以采用具有承袭性的显式的牛顿插值公式是不错的选择。 p n ( x ) f ( x 0 ) f ( x 0 , x 1 ) ( x − x 0 ) . . . f ( x 0 , x 1 , . . . …

如何用计算机做牛顿迭代公式,牛顿迭代法

牛顿迭代法(Newtons method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。 中文名 牛顿迭代法 外文名 Newtons method别 名 牛顿-拉夫逊(拉弗森)方法 提出时间 17世纪 牛顿迭代法产生背景 编辑…

牛顿恒等式 牛顿和

前言:仅个人小记。该恒等式推导逻辑非常简洁。目标:求一个多项式的所有根的次幂和。比如多项式 P ( x ) Σ i 0 n a i x i P(x)\Sigma_{i0}^{n}a_i x^i P(x)Σi0n​ai​xi的根为 α , β , . . . , ω \alpha,\beta,...,\omega α,β,...,ω&#xff…

牛顿插值公式

均差(差商) f[x0,x1]f(x1)−f(x0)x1−x0 一阶 f[x0,x1,x2]f(x1,x2)−f(x0,x1)x2−x0 二阶 ⋮ 性质 1.对上述二解均差展开,得, f[x0,x1,x2]f(x0)(x0−x1)(x0−x2)f(x1)(x1−x0)(x1−x2)f(x2)(x2−x0)(x2−x1) 依次类推 有&am…

5.3 牛顿-科茨公式

学习目标: 理解微积分基础知识,例如导数和微分的概念。学习牛顿-科茨公式的推导过程。这个公式实际上是使用泰勒公式对被积函数进行展开,并使用微积分的基本原理进行简化得到的。学习如何使用牛顿-科茨公式进行数值积分。这通常涉及到将被积…

牛顿迭代公式

问题背景 给定任意一个数x,求其平方根z,平方误差小于0.001。 这个问题直观的去想,我们一般会采取设定一个初始值,然后通过迭代逐渐逼近平方根,但是初始值怎样去迭代才能更快”逼近“成为关键问题,牛顿迭代…

人工智能数学基础---定积分3:微积分基本公式(牛顿-莱布尼茨公式)

一、引言 在《人工智能数学基础—定积分1:定积分的概念以及近似计算》介绍了利用定积分的定义进行定积分的近似计算方法,但这种方式比较复杂,如果被积函数复杂困难更大,那么定积分是否有其他计算方式呢?答案是肯定的&…

二分法求解方程的根java_【数值分析】利用二分法和牛顿公式求解方程的根

1.实验内容 ​分别利用牛顿公式和二分法对某一方程(此实验是以开方公式为准,即x2-c0,在验证时取c115)进行求解。且对两者的求解结果进行比较,比较两者的迭代次数和精度。 分别编写函数Binary(min, max, times)和 Newton(x0, times)实现以上两种方法。实验…

验证牛顿公式的局部收敛性,并找到对于牛顿公式不收敛(发散)的函数,比较二分法与牛顿公式的收敛速度

文末有代码,大家可以自己跑一下,体会一下牛顿法的运算过程 二、实验目的: a.验证牛顿公式的局部收敛性; b.比较二分法与牛顿公式的收敛速度; c.验证求解结果的正确性; 三、实验内容 a.在验证牛顿公式的…

牛顿迭代公式(详细)

牛顿迭代公式 X n 1 X n − f ( x ) f ′ ( x ) X_{n1} X_n -\frac{f(x)}{f(x)} Xn1​Xn​−f′(x)f(x)​ 上网搜了很久,搞懂了一点,简单记录一下 其实弄懂了一点后会发现它并不是很高大上😅 . 先来一段代码 求9的平方根,java实现 public static void main…

牛顿-莱布尼茨公式

牛顿-莱布尼兹公式(Newton-Leibniz formula),通常也被称为微积分基本定理,揭示了定积分与被积函数的原函数或者不定积分之间的联系。 牛顿-莱布尼茨公式的内容是一个连续函数在区间 [ a,b ] 上的定积分等于它的任意一个…

python语言培训是密封式的吗

述(最多18字 以下试题内容来源由-众课帮-公众号和小程序提供 可查询更多的试题答案新鲜尿液有氨臭味 变异性心绞痛患者首选药物是 A_______ofdependenceonGMOseedsandchemicalfertilizers,pesticides(杀虫剂),andherbicides(除草剂)isthencre…

【业界分享】字节跳动如何用 7 年,成为腾讯最可怕的对手?张一鸣一语道破...

点击上方,选择星标或置顶,每天给你送干货! 阅读大概需要16分钟 跟随小博主,每天进步一丢丢 转载自公众号:开发者技术前线 2019 年,字节跳动被预估广告收入可达 1000 亿元。 说到互联网巨头,很多…

VR旅游应用案例解析,世界那么大用VR去看看!

中国旅游研究院(文化和旅游部数据中心)发布“2019年上半年全国旅游经济运行情况”中显示上半年旅游经济平稳运行,预计国内旅游人数30.8亿人次,国内旅游收入2.78万亿元,同比分别增长8.8%和13.5%。由相关数据显示,旅游消费如今已经成为民众的一个重要生活方式。 同时为了不断…

从虚机到容器,秒拍架构师告诉你如何平滑进行业务迁移

近期,炫一下(北京)科技有限公司(简称“一下科技”)短视频产品“秒拍”完成了一个“大动作”——将原来部署在虚拟机上的主体业务迁移到华为云,同时将公司的技术体系承载在下一代虚拟技术容器(Do…

git中如何取消忽略文件

问题现象描述: 在每天的git-----pull时,操作失败。报文件冲突的异常。而该冲突文件却是自己已被忽略的文件,在网上通用的在.gitignore文件中取消忽略的办法无法实现,因为.gitignore文件中根本没有哪行命令是决定该文件的忽略操作…

git忽略文件不生效问题解决

git忽略文件不生效问题解决 文章目录 git忽略文件不生效问题解决**一 .gitignore添加了忽略文件,但是提交时还会出现这些忽略文件** 一 .gitignore添加了忽略文件,但是提交时还会出现这些忽略文件 —在gitignore中忽略了.idea文件夹,但是提交时仍旧会出…