Java多线程(一)多线程概要

多线程概要

多线程概要

什么是进程?

进程的特点:

什么是多线程

多线程编程:

 创建线程

1.继承 Thread 类

2.实现 Runnable 接口

多线程的优势

中断问题:

1. 通过共享的标记来进行沟通

2. 调用 interrupt() 方法来通知

等待一个线程-join()

多线程概要

什么是进程?

在冯诺依曼体系下,整个计算机设备分为,应用程序,操作系统,处理器(cpu),主存,I/O设备。应用程序在操作系统的调节下在处理器上进行合理的资源分配,而在其中一个运行起来的程序,就是进程。

cpu有一个概念,核心数和线程,核心为物理核心,线程为逻辑核心

而进程管理其实分为两步:

        1.描述一个进程:使用结构体或类,把一个进程有哪些信息,表示出来。

        2. 组织这些进程:使用一定的数据结构,把这些结构体/对象,放在一起。

进程的特点:

  1.   PID :每个进程需要有一个唯一的身份标识
  2.   内存指针:当前这个进程使用的内存是哪一部分,进程一旦开启,就会消耗一定的硬件资源
  3.  文件描述符:进程每次打卡一个文件,就会产生一个“文件描述符”  ,被标识了的意味着这个文件已打开。而一个进程会打开多个文件,然后呢就会把这些文件描述符放到循序表中,构成文件描述符表
  4. 进程调度:
  • 进程状态:就绪态,阻塞态,前者表示该进程已准备好,可以随时上cpu上执行,后者还需等待
  • 进程优先级:那个进程优先级高就先执行那个进程
  • 进程的上下文:就是描述了当前进程执行到哪里这样的“存档记录”,进程在离开CPU的时候就要把当前运行的中间结果存档在cpu的寄存器中,等到下次进程回来CPU上,在恢复之前的存档,从上次结果开始
  • 进程的记账信息:统计了每个进程,在CPU上执行了多久,可以作为调度的参考依据。
  • 并发和并行:指的是多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。它们虽然都说是"多个进程同时运行",但是它们的"同时"不是一个概念。并行的"同时"是同一时刻可以多个进程在运行(处于running),并发的"同时"是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺骗用户的现象

内存分配:

        操作系统给进程分配的内存,是以“虚拟地址空间”的方式进行分配。

什么是多线程

之前说过,进程是一个运行程序,然而一个程序内的功能有很多个,而这其中就有一个问题,就是客户可能会同时用一个程序的多个功能。诺是按照以前我们的写发就是一个main方法,去实现一个主要功能,肯定是不行的。为了应对这个情况,多线程运行就在所难免。

需求决定技术发展

线程是更轻量的的进程。约定一个进程可以包含多个线程,此时多个线程每个线程都是一个独立可以调度执行的执行流(并发),这些线程公用同一份进程的系统资源。

  1. 创建线程比创建进程更快.
  2. 销毁线程比销毁进程更快.
  3. 调度线程比调度进程更快.

可以理解为,一个工厂(进程),中有很多个生产线:(线程)(调用同一份资源,内存空间,文件描述符)。

其中几个问题要重点理解。一个厂子也就意味着资源和场地是一定的,如果为了生产效率,盲目去增加生产线,不去顾忌这些,反而会使的整个生成效率变慢。同理一个主机的核心也是有限,所以增加的线程数和进程数也是有限度。而一台主机到限度了,就可以增加另一台主机,从而使得核心数增加(也就是分布式处理)。

进程和线程的区别:

1.进程包含线程

2.进程有自己独立的内存空间和文件描述符,同一个进程的多个线程之间,共享同一份地址空间和文件描述符

3.进程是操作系统资源分配的基本单位,线程是操作系统调度的基本单位

4.进程之间具有独立性,一个进程挂了,不会影响到别的进程;同一个进程里的多个线程之间,一线程挂了,可能会把整个进程带走,会影响到其他线程的。

多线程编程:

Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装。

操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库)

这是我们第一个多线程。

public class ThreadDemo {private static class MyThread extends Thread {@Overridepublic void run() {Random random = new Random();while (true) {// 打印线程名称System.out.println(Thread.currentThread().getName());try {// 随机停止运行 0-9 秒Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();Random random = new Random();while (true) {// 打印线程名称System.out.println(Thread.currentThread().getName());try {Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {// 随机停止运行 0-9 秒e.printStackTrace();}}}
}

 创建线程

1.继承 Thread
class MyThread extends Thread {@Overridepublic void run() {System.out.println("这里是线程运行的代码");}
}

  创建一个线程实例

MyThread t = new MyThread();

   调用 start 方法启动线程

t.start(); // 线程开始运行
2.实现 Runnable 接口
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("这里是线程运行的代码");}
}

创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数

Thread t = new Thread(new MyRunnable());

调用start方法

t.start(); // 线程开始运行
class MyRunnabble implements Runnable{@Overridepublic void run() {while (true){System.out.println("123__true");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class test1 {public static void main(String[] args) {MyRunnabble runnabble=new MyRunnabble();Thread t=new Thread(runnabble);t.start();while (true) {System.out.println("main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}
  1. 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用.
  2. 实现 Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

常见方法:

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名

常见属性:

// 使用匿名类创建 Thread 子类对象

Thread t1 = new Thread() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Thread 子类对象");

  }

};

// 使用匿名类创建 Runnable 子类对象

Thread t2 = new Thread(new Runnable() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Runnable 子类对象");

  }

});

// 使用 lambda 表达式创建 Runnable 子类对象

Thread t4 = new Thread(() -> {

   System.out.println("使用匿名类创建 Thread 子类对象");

});

多线程的优势

1. 增加运行速度,通过记录时间戳

        使用 System.nanoTime() 可以记录当前系统的纳秒级时间戳.

        

public class test3 {static int count=0;public synchronized static void sum(){count++;}public static void main(String[] args) throws InterruptedException {long time=System.currentTimeMillis();Thread t1=new Thread(()->{for (int i = 0; i < 10000; i++) {sum();}});Thread t2=new Thread(()->{for (int i = 0; i < 10000; i++) {sum();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);System.out.println(System.currentTimeMillis()-time);}
}
  1. ID 是线程的唯一标识,不同线程不会重复
  2. 名称是各种调试工具用到
  3. 状态表示线程当前所处的一个情况,下面我们会进一步说明
  4. 优先级高的线程理论上来说更容易被调度到
  5. 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  6. 是否存活,即简单的理解,为 run 方法是否运行结束了
  7. 线程的中断问题,下面我们进一步说明

中断问题:

一个程序要执行很多次,可是我们突然有了一个需求要添加,就得让这个程序停下来,所以我就需要线程中断。

目前常见的有以下两种方式:

1. 通过共享的标记来进行沟通

注意变量捕获,但是java中要求变量捕获,捕获的变量的必须要final或者“实际final”及没有用final修饰,但是代码中没有做出修改。

public class ThreadDemo {private static class MyRunnable implements Runnable {public volatile boolean isQuit = false;@Overridepublic void run() {while (!isQuit) {System.out.println(Thread.currentThread().getName()+ ": 转账");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 让李四开始转账。");thread.start();Thread.sleep(10 * 1000);System.out.println(Thread.currentThread().getName()+ ": 通知李四对方是个骗子!");target.isQuit = true;}
}
2. 调用 interrupt() 方法来通知

使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定

义标志位.

public class ThreadDemo {private static class MyRunnable implements Runnable {@Overridepublic void run() {// 两种方法均可以while (!Thread.interrupted()) {//while (!Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName()+ ": 转账!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}}}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 开始转账。");thread.start();Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+ ": 对方是个骗子!");thread.interrupt();}
}
方法说明
public void interrupt()

中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位

public static boolean

interrupted()

判断当前线程的中断标志位是否设置,调用后清除标志位

public boolean

isInterrupted()

判断对象关联的线程的标志位是否设置,调用后不清除标志位

thread 收到通知的方式有两种(这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到):

1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通

知,清除中断标志

  • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

2. 否则,只是内部的一个中断标志被设置,thread 可以通过

  • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
  • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

注意:interrupt():作用设置标志位true,如果该线程在阻塞中,此时会把阻塞状态唤醒,抛出异常的方式中断。(当sleep(也可看做阻塞)被唤醒会自动把interrupted,将标志位清空)

产生阻塞的方法,会使得看到标识位为true,任然会抛出异常和清空标志,如果设置interrupt的时候,阻塞巧合醒了,这个时候程序执行到下一个循环判断条件就结束了。

等待一个线程-join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。这样可以让线程变得可控。线程的调度是随机的,无法判定两个线程谁先结束,谁先开始。而jion就是确定谁先开始的方法。

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度
public class test2 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(){@Overridepublic void run() {while (true) {System.out.println("123545_run");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};t.start();t.join();while (true) {System.out.println("123545_run");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

NEW: 安排了工作, 还未开始行动

RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.

BLOCKED: 这几个都表示排队等着其他事情

WAITING: 这几个都表示排队等着其他事情

TIMED_WAITING: 这几个都表示排队等着其他事情

TERMINATED: 工作完成了.

public class ThreadState {public static void main(String[] args) {for (Thread.State state : Thread.State.values()) {System.out.println(state);}}
}

BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.

TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python散点图

散点图 散点图是指在回归分析中&#xff0c;数据点在直角坐标系平面上的分布图&#xff0c;散点图表示因变量随自变量而变化的大致趋势&#xff0c;据此可以选择合适的函数对数据点进行拟合。用两组数据构成多个坐标点&#xff0c;考察坐标点的分布&#xff0c;判断两变量之间…

显示器鼠标滚动时或者拖拽文字变为绿色

新电脑&#xff0c;新显示器&#xff0c;看文章时滚动鼠标滑轮&#xff0c;文字颜色就变为绿色。 拖住文本文档或者浏览器等有文字的窗口&#xff0c;文字也会变为绿色。 静止时一点儿问题没有。 以下视频展示滚动和拖拽的操作&#xff0c;视频看不出变色&#xff0c;只参考…

科技云报道:AI时代,对构建云安全提出了哪些新要求?

科技云报道原创。 随着企业上云的提速&#xff0c;一系列云安全问题也逐渐暴露出来&#xff0c;云安全问题得到重视&#xff0c;市场不断扩大。 Gartner 发布“2022 年中国 ICT 技术成熟度曲线”显示&#xff0c;云安全已处于技术萌芽期高点&#xff0c;预期在2-5年内有望达到…

AOI软件之 CAD图纸导入功能

在这里&#xff0c;我不过多的解释AOI&#xff0c;半导体检测行业内的小伙伴自然会懂&#xff1b;我也不会过多解释何为diemap或者wafer-layout。因为我们本文的核心场景仅仅是cad图纸的解析和基本绘图的二次开发。而且我们紧紧是面向行业内的场景需求来说明此功能。 无图我说…

【Kafka】Kafka再平衡机制及相关参数

背景 Kafka作为一款基于发布订阅模式的消息队列&#xff0c;生产者将消息发送到Kafka集群&#xff08;Brokers&#xff09;中&#xff0c;消费者&#xff08;Consumer Group &#xff09;拉取消息进行消费&#xff0c;实现了异步机制。Kafka中&#xff0c;消费者通常以消费者组…

【Sentinel】ProcessorSlotChain处理器插槽链与Node

文章目录 1、Sentinel的基本概念2、ProcessorSlotChain3、Node 1、Sentinel的基本概念 Sentinel实现限流、隔离、降级、熔断等功能&#xff0c;本质要做的就是两件事情&#xff1a; 统计数据&#xff1a;统计某个资源的访问数据&#xff08;QPS、RT等信息&#xff09;规则判断…

Redis高并发分布式锁实战

高并发场景秒杀抢购超卖bug实战重现 秒杀抢购场景下实战JVM级别锁与分布式锁 大厂分布式锁Resisson框架实战 Lua脚本语言快速入门与使用注意事项 Redisson分布式锁源码剖析 Redis主从架构锁失效问题解析 从CAP角度剖析Redis与Zookeeper分布式锁区别 Redlock分布式锁原理与…

Qt QTreeWidge解决setItemWidget后,导致复选框失效

一、问题&#xff1a; QTreeWidget某一项加上itemWidget后&#xff0c;导致复选框失效问题 二、解决方法 将要加上的widget控件加到该项的后续的列&#xff0c;即控件跟复选框不同一列 三、具体代码 QTreeWidget* treeW new QTreeWidget; treeW->setColumnCount(2); /…

centos编译升级cmake,痛苦的Linux小白

环境 root 用户 下载 cmake官网下载地址&#xff1a;https://cmake.org/download/ 获取下载地址&#xff0c;右击cmake-3.27.4.tar.gz 命令行输入链接地址&#xff0c;下载 wget https://github.com/Kitware/CMake/releases/download/v3.27.4/cmake-3.27.4.tar.gz解压 tar -zx…

Git_回退到上一次commit与pull

git 回退到上个版本 rollback 回滚 git reset HEAD&#xff0c; git 回退到上一版本

MySQL 连接查询

文章目录 1.什么是连接查询2.连接类型内连接交叉连接左连接右连接自然连接 3.连接条件4.隐式连接使用逗号连接表逗号与 JOIN 的优先级 5.全外连接6.小结参考文献 1.什么是连接查询 在关系型数据库管理系统&#xff08;RDBMS&#xff09;中&#xff0c;连接查询是一项重要的数据…

桉木板材的优缺点

桉木&#xff08;Eucalyptus&#xff09;是一种常见的木材品种&#xff0c;具有一些独特的特点和用途。以下是桉木板材的一些优点和缺点&#xff1a; 优点&#xff1a;强度高&#xff1a;桉木具有较高的密度和强度&#xff0c;使其在承重和结构应用中表现出色。它的强度比一些其…

C# 命令行参数分割

CommandLineToArgvW 函数 [DllImport("shell32.dll", SetLastError true)] private static extern IntPtr CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs); 参数&#xff1a; [in] lpCmdLine 类型&#xff1a;…

C++学习笔记(堆栈、指针、命名空间、编译步骤)

C 1、堆和栈2、指针2.1、指针的本质2.2、指针的意义2.3、清空指针2.4、C类中的this 3、malloc and new4、命名空间4.1、创建命名空间4.2、使用命名空间 5、编译程序的四个步骤5.1、预处理5.2、编译5.3、汇编5.4、链接 1、堆和栈 堆&#xff08;heap&#xff09;和栈&#xff0…

Jenkins Jenkinsfile管理 Pipeline script from SCM

一、Jenkinsfile理解 Jenkins Pipeline 提供了一套可扩展的工具&#xff0c;用于将“简单到复杂”的交付流程实现为“持续交付即代码”。Jenkins Pipeline 的定义通常被写入到一个文本文件&#xff08;称为 Jenkinsfile &#xff09;中&#xff0c;该文件可以被放入项目的源代码…

RK开发板的USB连接(Ubuntu)

一、安装连接工具 sudo apt-get install putty 二、启动putty工具 sudo putty 三、连接usb&#xff0c;并查看相关的信息 # 查看接入的是否有usb ls /dev/tty* 显示如下&#xff1a;&#xff08;含有usb接口&#xff1a; /dev/ttyUSB0&#xff09; /dev/tty /dev/tty23 /d…

设计模式-01简单工厂模式详解 详细代码对比

目录 ChatGpt问答原生代码简单工厂模式代码 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;新增boat 对比两种方法原生代码为什么使用强制转换&#xff1f;简单工厂模式 简单工厂方法总结与原生代码的区别&#xff1a;优点:缺点&#xff1a; 参考 本文将介绍什么…

直接接入电商API接口实现调用封装好的商品详情SKU数据参数及返回

什么是API&#xff1f; API全称为Application Programming Interface&#xff0c;中文是应用程序编程接口。它其实是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工…

Python判断多个文件夹的文件夹名是否包含“分公司”或“营销中心”怎么处理?(方法一)...

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 晓畅军事&#xff0c;试用于昔日。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者群【哎呦喂 是豆子&#xff5e;】问了一个Python自…

【日常笔记】使用Server过程中可能遇到的一些问题

使用Server过程中可能遇到的一些问题 1. 如何查找GPU型号与驱动版本之间的关系&#xff1f;2. 如何查看当前Server的内核版本&#xff1f;3. 使用Nvidia过程中可能用到的命令4. 对Jupyter Notebook的一些配置5. TensorFlow的一般操作6. 使用PyTorch的一些操作7. 修改安装源为国…