【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 {
		 @Override
		 public 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();
          }
       }
    }
    

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EVS9329-ES驱动器EVS9329ES可议价

EVS9329-ES驱动器EVS9329ES可议价 EVS9329-ES驱动器EVS9329ES可议价 EVS9329-ES驱动器EVS9329ES可议价 EVS9329-ES驱动器EVS9329ES可议价 EVS9329-ES驱动器EVS9329ES可议价 EVS9329-ES步进电机按结构分类&#xff1a;步进电动机也叫脉冲电机&#xff0c;包括反应式步进电动…

Unity射击游戏开发教程:(27)创建带有百分比的状态栏

创建带有弹药数和推进器百分比的状态栏 在本文中,我将介绍如何创建带有分数和百分比文本的常规状态栏。 由于 Ammo Bar 将成为 UI 的一部分,因此我们需要向 Canvas 添加一个空的 GameObject 并将其重命名为 AmmoBar。我们需要一个文本和两个图像对象,它们是 AmmoBar 的父级。…

13- 函数的定义与使用+形参实参区分

13- 函数的定义与使用形参实参区分 文章目录 13- 函数的定义与使用形参实参区分一、函数的定义与使用1.1 函数的结构1. 函数头2. 函数体 1.2 示例代码例子 1&#xff1a;无参数和无返回值的函数例子 2&#xff1a;带参数和返回值的函数 1.3 函数的基本语法1.4 函数的使用示例例…

多点液位传感器如何实现连续液位检测

如今&#xff0c;随着液位传感器的不断发展与演进&#xff0c;多点液位传感器也应用而生&#xff0c;可以实现对液体在多个连续点位的精确检测与监控&#xff0c;在洗地机设备上&#xff0c;可以及时了解水量&#xff0c;避免水资源浪费等情况。 多点式光电液位传感器采用了先…

测试记录4:在windows wsl2上配置ubuntu20.04

1.下载ubuntu20.04 (1) 在microsoft store中下载ubuntu20.04 (2) 在powershell中检查ubuntu20.04 wsl --listwsl -l -v安装成功 2.安装界面 见测试记录3 3.安装必要的功能包 sudo apt install zip sudo apt install gedit4.安装ros2 wget http://fishros.com/install -O …

提升你的编程体验:自定义 PyCharm 背景图片

首先&#xff0c;打开 PyCharm 的设置菜单&#xff0c;点击菜单栏中的 File > Settings 来访问设置&#xff0c;也可以通过快捷键 CtrlAItS 打开设置。 然后点击Appearance & Behavior > Appearance。 找到Background image...左键双击进入。 Image:传入自己需要设置…

蓝卓为中小制造企业注入数字化转型活力

随着劳动力成本上升,原材料价格上涨,企业生产成本逐年增加&#xff0c;市场竞争越来越激烈&#xff0c;传统的中小制造企业面临着巨大的压力。 通过数字化转型应对环境的变化已成为行业共识&#xff0c;在数字化的进程中&#xff0c;中小企业首要考虑生存问题&#xff0c;不能…

什么是场外期权?场外期权有几种做法?

今天带你了解什么是场外期权&#xff1f;场外期权有几种做法&#xff1f;期权分为场内期权&#xff0c;场外期权。场内期权我们都知道&#xff0c;是在期货盘里购买的期权&#xff0c;但场外期权呢&#xff1f; 什么是场外期权&#xff1f; 场外期权是一种在交易所之外进行交易…

数据结构和矩阵细节用法:double、cell和complex #matlab

矩阵建立 建立矩阵用[]&#xff1b; 矩阵的同一行内的元素用逗号或者空格隔开&#xff1b; 矩阵的不同行的元素用分号隔开 eg. 矩阵 A 1 2 3 4 5 6 7 8 9 在matlab中矩阵A表示为&#xff1a; clc;clear; A[1,2,3;4,5,6;7,8,9]; %或者A[1 2 3;4 5 …

helm升级部署时出现升级挂起状态处理

问题 在使用helm 升级命令时&#xff0c;升级命令如下&#xff1a; helm upgrade -i -f ./values-prod.yaml myapp ./ -n myns --create-namespace中途因为网络原因&#xff0c;再次运行上面升级命令时出现&#xff0c;如下错误&#xff1a; Error: UPGRADE FAILED: another …

《数据结构》

简答题 一、设散列函数H(key)=key MOD 11,用线性探测再散列法解决冲突。对关键字序列{ 13,28,72,5,16,18,7,11,24 }在地址空间为0-10的散列区中建散列表,画出此表,并求等概率情况下查找成功时的平均查找长度。 散列函数为 H(key)=key MOD 11,将关键字序列 {13,28,…

【数据结构】【版本1.1】【线性时代】——单链表

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、顺序表的问题二、链表的概念三、单链表的模拟实现3.1 定义3.2 打印3.3 创建新节点3.4 头插3.5 尾插3…

Android MediaMetadataRetriever获取视频宽高,Java

Android MediaMetadataRetriever获取视频宽高&#xff0c;Java public static int[] getVideoSize(Context ctx, Uri uri) {MediaMetadataRetriever retriever new MediaMetadataRetriever();int[] size {-1, -1}; //宽&#xff0c;高try {retriever.setDataSource(ctx, uri)…

JVC摄像机SD卡变成RAW的恢复方法

JVC小日本胜利公司&#xff0c;公司名字绕口且产品线极广&#xff0c;涉及汽车、影音、娱乐……&#xff0c;而JVC在摄像机产品方面也有涉及&#xff0c;不过市场上极为少见。下边我们来看下这个JVC摄像机MP4恢复案例。 故障存储: 32G存储卡 RAW文件系统 故障现象: 客户无…

Linux Radix tree简介

文章目录 前言一、Radix tree简介二、Operations2.1 Lookup2.2 Insertion2.3 Deletion 三、Linux内核API3.1 初始化3.2 radix_tree_insert/delete3.3 radix_tree_preload3.4 radix_tree_lookup3.5 radix_tree_tag_set3.6 radix_tree_tagged 四、address_space4.1 简介4.2 相应数…

新一代大核卷积反超ViT和ConvNet!同参数量下性能、精度、速度完胜

大核卷积网络是CNN的一种变体&#xff0c;也是深度学习领域的一种重要技术&#xff0c;它使用较大的卷积核来处理图像数据&#xff0c;以提高模型对视觉信息的理解和处理能力。 这种类型的网络能够捕捉到更多的空间信息&#xff0c;因为它的大步长和大感受野可以一次性覆盖图像…

34万汉语词语成语反义词ACCESS\EXCEL数据库

反义词就是两个意思相反的词&#xff0c;包括&#xff1a;绝对反义词和相对反义词。分为成对的意义相反、互相对立的词。如&#xff1a;真——假&#xff0c;动——静&#xff0c;拥护——反对。这类反义词所表达的概念意义互相排斥。或成对的经常处于并举、对待位置的词。如&a…

WinForm之TCP服务端

目录 一 原型 二 源码 一 原型 二 源码 using System.Net; using System.Net.Sockets; using System.Text;namespace TCP网络服务端通讯 {public partial class Form1 : Form{public Form1(){InitializeComponent();}TcpListener listener null;TcpClient handler null;Ne…

记C#优化接口速度过程

前提摘要 首先这个项目是接手的前一任先写的项目&#xff0c;接手后&#xff0c;要求对项目一些速度相对较慢的接口进行优化&#xff0c;到第一个速度比较慢的接口后&#xff0c;发现单接口耗时4-8秒&#xff0c;是的&#xff0c;请求同一个接口&#xff0c;在参数不变的情况下…

如何在CST软件中获得多天线不同频的SAR

之前写过计算SAR的文章&#xff0c;但是没有提到多天线的情况。 仿真实例018&#xff1a;均匀头模型和天线SAR比吸收率仿真案例 CST软件如何用E场计算Loss损耗密度 --- SAR计算加速技巧 这期我们看看多天线不同频率如何计算SAR。 用一个简单的手模型和三个不同长度天线为例&a…