【Java并发编程之美 | 第一篇】并发编程线程基础

在这里插入图片描述

文章目录

  • 1.并发编程线程基础
    • 1.1什么是线程和进程?
    • 1.2线程创建与运行
      • 1.2.1继承Thread类
      • 1.2.2实现Runnable接口
      • 1.2.3实现Callable接口(与线程池搭配使用)
      • 1.2.4小结
    • 1.3线程常用方法
      • 1.3.1线程等待与通知
      • 1.3.2线程睡眠
      • 1.3.3让出CPU执行权
      • 1.3.4线程中断
    • 1.4理解线程上下文切换
    • 1.5线程死锁
      • 1.5.1什么是线程死锁?
      • 1.5.2如何避免死锁?

1.并发编程线程基础

1.1什么是线程和进程?

  1. 线程是进程中的一个实体,线程本身是不会独立存在的,线程则是进程的一个执行路径
  2. 进程是系统进行资源分配的基本单位,线程是CPU分配的基本单位
  3. 进程例子:我们在电脑上启动的一个个应用,比如我们启动一个浏览器,就会启动了一个浏览器进程
  4. 线程例子:在 Java 程序中启动的一个 main 函数,即启动了一个JVM进程,而main函数所在的线程就是这个进程中的一个线程,称为主线程

image-20240614185816073

1.2线程创建与运行

  1. Java中创建线程主要有三种⽅式,分别为继承Thread类、实现Runnable接口、实现Callable接口。

1.2.1继承Thread类

  1. 继承Thread类,重写run()⽅法,调⽤start()⽅法启动线程
public class ThreadTest {/*** 继 承Thread类**/public static class MyThread extends Thread {@Overridepublic void run () {System.out.println( "This is child thread" ) ;}}public static void main ( String [] args) {MyThread thread = new MyThread ();thread.start();}
}

1.2.2实现Runnable接口

  1. 实现 Runnable 接口,重写 run() 方法
  2. 然后创建 Thread 对象,将 Runnable 对象作为参数传递给 Thread 对象,调用 start() 方法启动线程。
class RunnableTask implements Runnable {public void run() {System.out.println("上岸、上岸!");}public static void main(String[] args) {RunnableTask task = new RunnableTask();Thread thread = new Thread(task);thread.start();}
}

1.2.3实现Callable接口(与线程池搭配使用)

  1. 实现 Callable 接口,重写 call() 方法
  2. 然后创建 FutureTask 对象,参数为 Callable 对象;紧接着创建 Thread 对象,参数为 FutureTask 对象,调用 start() 方法启动线程。
  3. 通过 实现Callable接口的对象 的get方法获取返回结果
class CallableTask implements Callable<String> {public String call() {return "上岸、上岸了!";}public static void main(String[] args) throws ExecutionException, InterruptedException {CallableTask task = new CallableTask();FutureTask<String> futureTask = new FutureTask<>(task);Thread thread = new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}

1.2.4小结

image-20240421103020296

1.3线程常用方法

  1. 线程等待方法:wait()、wait(long timeout)、wait(long timeout,int nanos)
  2. 线程通知方法:nodify()、notifyAll()
  3. 让出优先权:yield()
  4. 线程中断方法:interrupt()、isinterrupted()、interrupted()
  5. 线程休眠方法:sleep()

1.3.1线程等待与通知

线程等待方法:

  1. wait():当一个线程 A 调用一个共享变量的 wait() 方法时,线程 A 会被阻塞挂起,直到发生下面几种情况才会返回 :

    1.1 线程 B 调用了共享对象 notify()或者 notifyAll() 方法;

    1.2 其他线程调用了线程 A 的 interrupt()方法,线程 A 抛出 InterruptedException 异常返回。

  2. wait(long timeout) :这个方法相比 wait() 方法多了一个超时参数,它的不同之处在于,如果线程 A 调用共享对象的 wait(long timeout)方法后,没有在指定的 timeout 时间内被其它线程唤醒,那么这个方法还是会因为超时而返回。、

  3. wait(long timeout, int nanos),其内部调用的是 wait(long timout) 方法。

唤醒/通知线程主要有下面两个方法:

  1. notify():一个线程 A 调用共享对象的 notify() 方法后,会唤醒一个在这个共享变量上调用 wait 系列方法后被挂起的线程。一个共享变量上可能会有多个线程在等待,具体唤醒哪个等待的线程是随机的
  2. notifyAll():不同于在共享变量上调用 notify()方法会唤醒被阻塞到该共享变量上的一个线程,notifyAll 方法会唤醒所有在该共享变量上调用 wait 系列方法而被挂起的线程。

join():等待线程执行终止

  1. 如果一个线程 A 执行了 thread.join(),当前线程 A 会被阻塞,即等待 thread 线程执行终止之后才从 thread.join() 返回

1.3.2线程睡眠

  1. sleep(long millis):Thread 类中的静态方法,当一个执行中的线程 A 调用了 Thread 的 sleep 方法后,线程 A 会暂时让出指定时间的执行权
  2. 但是线程 A 所拥有的监视器资源,比如锁,还是持有不让出的。指定的睡眠时间到了后该方法会正常返回,接着参与 CPU 的调度,获取到 CPU 资源后就可以继续运行

1.3.3让出CPU执行权

  1. yield():Thread 类中的静态方法,当一个线程调用 yield 方法时,实际是在暗示线程调度器,当前线程请求让出自己的 CPU

1.3.4线程中断

  1. Java 中的线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行

  2. void interrupt():中断线程

    2.1 例如:当线程A运行时,线程B可以调用线程A的interrupt()方法来设置线程A的中断标志为true并立即返回

    2.2 设置中断标志仅仅是标记,线程A并没有被中断,会继续往下执行

    2.3 但如果线程A因为调用wait、join、以及sleep方法而被阻塞挂起,这时线程B若调用线程A的interrupt()方法,线程A会在调用这些方法的地方抛出InterrupedException异常

  3. boolean isInterrupted():检测当前线程是否被中断,如果是返回true,否则返回false

  4. boolean interrupted():检测当前线程是否被中断,如果是返回true,否则返回false。与 isInterrupted 不同的是,该方法如果发现当前线程被中断,则会清除中断标志。

1.4理解线程上下文切换

  1. 在多线程编程中,线程个数一般都大于CPU个数,但是每个CPU同一时刻只能被一个线程使用
  2. 为了让用户感觉多个线程是在同时执行,CPU资源的分配采用了时间片轮转的方法,即给每个线程分配一个时间片,线程在时间片内占用CPU执行任务。当线程使用完时间片,就处于就绪状态并让出CPU让其他线程占用,即上下文切换

1.5线程死锁

1.5.1什么是线程死锁?

  1. 死锁是指两个或两个以上的线程在执行过程中,因为争夺资源而造成的互相等待的现象

  2. 产生死锁的四个条件:

    2.1 互斥性:资源是互斥的,同一时刻只能由一个线程占用

    2.2 请求并持有条件:一个线程已经占有一个资源,同时提出新的资源请求,并占据已有的资源不释放

    2.3 不可剥夺条件:线程获取到的资源在自己使用完之前不能被其他线程所占用

    2.4 环路等待条件:指在发生死锁时,必然存在一个线程一资源的环形链

  3. 代码举例:

    import java.util.Date;public class LockTest {public static String obj1 = "obj1";public static String obj2 = "obj2";public static void main(String[] args) {LockA la = new LockA();new Thread(la).start();LockB lb = new LockB();new Thread(lb).start();}
    }
    class LockA implements Runnable{public void run() {try {System.out.println(new Date().toString() + " LockA 开始执行");while(true){synchronized (LockTest.obj1) {System.out.println(new Date().toString() + " LockA 锁住 obj1");Thread.sleep(3000); // 此处等待是给B能锁住机会synchronized (LockTest.obj2) {System.out.println(new Date().toString() + " LockA 锁住 obj2");Thread.sleep(60 * 1000); // 为测试,占用了就不放}}}} catch (Exception e) {e.printStackTrace();}}
    }
    class LockB implements Runnable{public void run() {try {System.out.println(new Date().toString() + " LockB 开始执行");while(true){synchronized (LockTest.obj2) {System.out.println(new Date().toString() + " LockB 锁住 obj2");Thread.sleep(3000); // 此处等待是给A能锁住机会synchronized (LockTest.obj1) {System.out.println(new Date().toString() + " LockB 锁住 obj1");Thread.sleep(60 * 1000); // 为测试,占用了就不放}}}} catch (Exception e) {e.printStackTrace();}}
    }
    
  4. 执行结果:

    image-20240614201836475

1.5.2如何避免死锁?

  1. 只要破坏产生死锁的四大条件中的一个即可,其中破坏环形等待条件最为容易,即保持资源申请的有序性就可以避免死锁

  2. 例子:

    class LockB implements Runnable{public void run() {try {System.out.println(new Date().toString() + " LockB 开始执行");while(true){synchronized (LockTest.obj1) {System.out.println(new Date().toString() + " LockB 锁住 obj2");Thread.sleep(3000); synchronized (LockTest.obj2) {System.out.println(new Date().toString() + " LockB 锁住 obj1");Thread.sleep(60 * 1000); }}}} catch (Exception e) {e.printStackTrace();}}
    }
    

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1451956.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

CATO原理中的数学与魔术(十三)——综合应用

早点关注我&#xff0c;精彩不错过&#xff01; 不知不觉&#xff0c;这个系列已经写了48篇文章&#xff0c;4篇数学理论介绍和3个系列共8篇魔术应用&#xff0c;相关内容请戳&#xff1a; CATO原理中的数学与魔术&#xff08;十二&#xff09;——CATO与MAT principle CATO原理…

[C#]使用C#部署yolov10的目标检测tensorrt模型

【测试通过环境】 win10 x64vs2019 cuda11.7cudnn8.8.0 TensorRT-8.6.1.6 opencvsharp4.9.0 .NET Framework4.7.2 NVIDIA GeForce RTX 2070 Super cuda和tensorrt版本和上述环境版本不一样的需要重新编译TensorRtExtern.dll&#xff0c;TensorRtExtern源码地址&#xff1a;T…

气膜球幕影院:科技创新的结晶—轻空间

气膜球幕影院集成了多项先进科技&#xff0c;打造出一种全新的沉浸式观影体验。让我们一起来了解这些科技创新背后的故事。 高分辨率投影技术 气膜球幕影院采用先进的高分辨率投影技术&#xff0c;通常支持4K甚至8K的超高清画质&#xff0c;保证了影像的细腻和逼真。无论是科幻…

LabVIEW软件开发任务的工作量估算方法

在开发LabVIEW软件时&#xff0c;如何准确估算软件开发任务的工作量。通过需求分析、功能分解、复杂度评估和资源配置等步骤&#xff0c;结合常见的估算方法&#xff0c;如专家判断法、类比估算法和参数估算法&#xff0c;确保项目按时按质完成&#xff0c;提供项目管理和资源分…

十大成长型思维:定位思维、商业思维、时间管理思维、学习成长思维、精力管理思维、逻辑表达思维、聚焦思维、金字塔原理、目标思维、反思思维

一、定位思维 定位思维是一种在商业和管理领域中至关重要的思维模式&#xff0c;它涉及到如何在顾客心智中确立品牌的独特位置&#xff0c;并使其与竞争对手区分开来。以下是关于定位思维的清晰介绍&#xff1a; 1、定义 定位思维是一种从潜在顾客的心理认知出发&#xff0c;通…

自动生成企业培训视频:创新与效率的完美结合

前言 随着人工智能技术的飞速发展&#xff0c;大模型技术在各个领域的应用日益广泛。在企业培训领域&#xff0c;大模型技术的应用为培训视频的生成带来了革命性的变革。本文将探讨如何利用大模型技术自动生成企业培训视频&#xff0c;以及这一技术为企业培训带来的创新和效率…

Unity OpenCVForUnity 安装和第一个案例详解 <一>

目录 一、资源简介 二、安装使用 1.下载案例Demo 2.移动StreamingAssets文件夹 3.添加场景 三、今日案例 1.案例Texture2DToMat Example 2.什么是Mat&#xff1f; 3.如何把Texture2D变成Mat &#xff08;1&#xff09;.初始化Mat &#xff08;2&#xff09;.Cv_…

门控循环单元GRU与长短期记忆网络LSTM

门控循环单元与长短期记忆网络 门控隐状态 问题提出&#xff1a;对于一个序列来说不是每个观察值都是同等重要想只记住相关的观察需要&#xff1a; 能关注的机制&#xff08;更新门&#xff09;能遗忘的机制&#xff08;重置门&#xff09; 第一个词元的影响至关重要。 我们…

变压器绕组内部故障的Simulink仿真

​利用变压器纵联差动保护的Simulink仿真模型是无法进行变压器绕组内部故障仿真的。为了解决这一问题&#xff0c;可将图中的三相变压器模型改变为三个单相变压器 , 在变压器属性框中选中 “三绕组变压器” (Three windings Transformer), 从而构造出一个一次绕组, 两个二次绕组…

MySQL之优化服务器设置(二)

优化服务器设置 InnoDB事务日志(包含:Redo log 重做日志和Undo log回滚日志) 了解清楚"把日志缓冲写到日中文件"和"把日志刷新到持久化存储"之间的不同是很重要的。在大部分操作系统中&#xff0c;把缓冲写到日志只是简单地把数据从InnoDB的内存缓冲转移…

高考志愿填报,大学读什么专业比较好?

高考分数出炉后&#xff0c;选择什么样的专业&#xff0c;如何去选择专业&#xff1f;于毕业生而言是一个难题。因为&#xff0c;就读的专业前景不好&#xff0c;意味着就业情况不乐观&#xff0c;意味着毕业就是失业。 盲目选择专业的确会让自己就业时受挫&#xff0c;也因此…

【第7章】Vue之第一个Vue程序(Vue创建)

文章目录 前言一、创建1. 命令行2. 创建3. 安装依赖 二、启动三、访问总结 前言 接下来我们通过VSCode来创建我们的第一个Vue应用程序。 一、创建 1. 命令行 Terminal>New Terminal 2. 创建 #这一指令将会安装并执行 create-vue&#xff0c;它是 Vue 官方的项目脚手架工…

【Quartus 13.0】EP1C3144I7 部署4*6矩阵键盘

仿照 正点原子 的 Sample 修改 V2手册 P266 没有用这个 给出的手动按键控制的矩阵模块 为 4*6 矩阵键盘外接模块 每一个按键自带led&#xff0c;所以对应的接口是合并在一起的一个引脚 按下后 LED 亮&#xff0c;vice versa 底部 LED*8 目前不清楚有什么用 或许可以变成 16进…

人工智能在风险管理中的创新之路

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;尤其在风险管理领域&#xff0c;其展现出的巨大潜力令人瞩目。风险管理&#xff0c;作为一个涉及广泛领域的复杂系统&#xff0c;正逐渐依赖于AI技术来提升效率和准…

Folx软件下载及安装教程

简介&#xff1a; Folx Pro是一款适合Mac的专业下载工具也是一款BT下载器&#xff0c;Folx中文版有一个支持Retina显示的现代界面&#xff0c;提供独特的系统排序、存储下载内容与预览下载文件。Folx中文官网提供Folx教程、激活码、下载。 安 装 包 获 取 地 址&#xff1a; …

漫谈中国历史:《米小圈漫画历史》带大家领略古今变迁

在漫画的世界里&#xff0c;历史可以是生动有趣的&#xff0c;就像《米小圈漫画历史》展现的那样。这一套以米小圈形象为主的原创幽默中国历史漫画书&#xff0c;不仅让读者在娱乐中学习&#xff0c;更是一次穿越历史长河的奇妙冒险。在这篇文章中&#xff0c;我们将跟随米小圈…

(游戏:挑一张牌)编写程序,模拟从一副 52 张的牌中选择一张牌。

(游戏:挑一张牌)编写程序&#xff0c;模拟从一副 52 张的牌中选择一张牌。程序应该显示牌的 大小(Ace、2、3、4、5、6、7、8、9、10、Jack、Queen、King)以及牌的花色(Clubs (黑梅花)、Diamonds(红方块)、Hearts(红心)、Spades(黑桃))。下面是这个程序的 运行示例: The card yo…

Stable Diffusion【光影文字】:绚丽光影,文字与城市夜景的光影之约

今天我们我们结合城市夜景背景来看一下光影文字的效果&#xff0c;我们先来看一下效果图。 一. 字融城市夜景制作光影文字方法 【第一步】&#xff1a;制作底图这里制作底图使用黑底白字。我们使用美图秀秀制作一个"小梁子"字的底图。 字体&#xff1a;默认字体 图…

【数据挖掘】机器学习中相似性度量方法-欧式距离

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 路虽远&#xff0c;行则将至&#…

换卡槽=停机?新手机号使用指南!

刚办理的手机号莫名其妙的就被停用了&#xff1f;这到底是怎么回事&#xff1f;这篇文章快来学习一下吧。 ​ 先说一下&#xff0c;你的手机为什么被停机&#xff1f; 现在运营商对于手机卡的使用有着非常严格的要求&#xff0c;尤其是刚办理的新号码&#xff0c;更是“严上加…