day16_java多线程(入门了解)

多线程入门

一、线程和进程

  1. 进程

    进程:是指一个内存中运行的应用程序每个进程都有一个独立的内存空间和系统资源,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。进程是系统进行资源分配和调度的独立单位。

    单cpu同一时间点只能执行一件事情,CPU高效的切换让我们觉得是同时进行的

    我们在同一个进程内可以执行多个任务,每个任务就可以看成一个线程

    进程就是正在运行的程序
    进程是系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。

    案例:

    百度云盘(一个应用程序:进程)

    下载功能(可以同时下载多个文件)

  2. 线程

    线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

    简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

    在同一个进程内可以执行多个任务,而这个每个任务就是看成线程
    **线程,**是程序执行的单元,执行路径,是程序使用cpu最基本单位。

    cpu 只有一个, 每次只能执行一个(线程)

    一个进程有多个线程

    单线程 :如果程序只有只有一条执行路径 多线程:如果程序有多条执行路径

二、并行与并发

  1. 并发:逻辑上同时发生,指再某一个时间内同时运行的程序
  2. 并行:物理上同时发生,指在某一个时间点同时运行的程序

在这里插入图片描述

三、多线程的意义嘛?

多线程存在的意义:不是提高程序的执行速率,其实是为了提高程序的使用率。
程序的执行其实都是在抢cpu的资源,cpu的执行权。
多个线程抢夺到cpu执行权的概率更大 线程抢夺执行权具有随机性

四、java程序的运行原理

由java命令启动jvm,启动jvm相当于启动了一个进程

接着该进程创建主线程(main)去调用main方法

jvm虚拟机的启动是单线程的还是多线程的?多线程

原因是垃圾回收线程也要启动,不然很容易就内存溢出

五、Thread的基本使用

1、创建线程的步骤
  • 自定义一个类MyThread 继承Thread类
  • 重写run方法
  • 创建一个MyThread对象
  • MyThread对象.start()

注: run 与 start 的区别

  • 直接调用run方法,还是在main线程中执行
  • start() 方法, jvm会创建一个新线程,然后jvm会自动运行新线程的run方法
2、创建多个线程的方法

注:new 多个MyThread对象即可。不是要理解成调用多次start了

MyThread myThread = new MyThread("张三"); //这就是一个线程 
MyThread myThread2 = new MyThread("李四");
myThread.start();
myThread2.start();
3、获得线程的名字
  • String getName()
    返回该线程的名称。

    可以在Thread的子类中直接使用

  • Thread.currentThread() : 得到当前线程对象

System.out.println(Thread.currentThread().getName());
4、多线程独立栈空间

在这里插入图片描述

5、多线程的打印具有随机性

在这里插入图片描述

6、线程的调度

**分时调度:**所有线程轮流使用CPU 的使用权,平均分配每个线程占用 CPU 的时间。

**抢占式调度:**优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),

Java使用的是抢占式调度。

7、设置线程的优先级:

抢占式调度详解:大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我 们上课一边使用idea编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是 在同时运行,”感觉这些软件好像在同一时刻运行着“。 实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

在这里插入图片描述

线程优化级高,并不能让线程先执行。它还是随机的,只是概率高点

六、多线程好处:

  1. 充分利用CPU的资源(多进程), 多线程(为当前程序抢占CPU使用权)

  2. 简化编程模型

  3. 带来良好的用户体验

  4. 多个线程之间互不干扰

七、线程的控制

1、Thread类API

属性:

NORM_PRIORITY : 值为 5
MAX_PRIORITY : 值为 10
MIN_PRIORITY : 值为 1

构造方法:

  • Thread():分配一个新的 Thread对象。。

  • Thread(String name):分配一个指定名字的新的线程对象。

  • Thread(Runnable target):分配一个带有指定目标新的线程对象。

  • Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。

常用方法:

  • String getName():获取当前线程名称。
  • static Thread currentThread():返回对当前正在执行的线程对象的引用。
  • void setName(String name):将此线程的名称更改为等于参数 name 。
  • void start():导致此线程开始执行; Java虚拟机调用此线程的run方法。
  • void run():此线程要执行的任务在此处定义代码。
  • static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
  • int getPriority() :返回此线程的优先级。
  • void setPriority(int newPriority) :更改此线程的优先级。
  • void join() :等待这个线程死亡。
  • static void yield():对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。
  • void interrupt():中断这个线程。
  • boolean isAlive():测试这个线程是否活着。
  • Thread.State getState():返回此线程的状态。
2、线程的休眠
public void run() {// 放让线程执行代码块for(int i=0;i<10;i++){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName()+"我是最棒的:"+i);}
}
3、线程的加入

void join() :等待这个线程死亡。

MyThread myThread = new MyThread("张三"); //这就是一个线程
MyThread myThread2 = new MyThread("李四");
myThread.start();
try {myThread.join();
} catch (InterruptedException e) {throw new RuntimeException(e);
}
myThread2.start();
4、线程的礼让

static void yield():对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。

public void run() {
// 放让线程执行代码块
for(int i=0;i<10;i++){
Thread.yield(); //让出cpu 使用权
System.out.println(getName()+"我是最棒的:"+i);
}
}
5、线程的中断
  • public final void stop (): 让线程停止,过时了,但是还可以使用。
  • **public void interrupt ( )**∶中断线程。把线程的状态终止,并抛出一个InterruptedException.
6、线程的守护

public final void setDaemon(boolean on)

将此线程标记为daemon线程或用户线程。当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。

线程启动前必须调用此方法。

MyThread myThread = new MyThread("张三"); //这就是一个线程
MyThread myThread2 = new MyThread("李四");
myThread.setDaemon(true);
myThread2.setDaemon(true);
myThread.start();
myThread2.start();
//myThread.interrupt();for(int i=0;i<10;i++){System.out.println(Thread.currentThread().getName()+"我是最棒的:"+i);
}

八、Runnable创建多线程

runable方式创建线程
  1. 创建一个Runable接口的实现类MyRunable
  2. 重写run方法
  3. 创建实现类MyRunable对象, myrunable
  4. 创建Thread类的对象,把 myrunable对象作为构造参数传过去

九、创建多线程方式总结

实现多线程方式:两种

方法1:Thread类

  1. 自定义一个MyThread类继承Thread类
  2. 在MyThread类中重写run方法
  3. 创建MyThread类的对象
  4. 启动线程对象。start()方法

方法2:Runable 接口

  1. 定义一个Runable接口的实现类,MyRunable类
  2. 在MyRunable类中重写run方法
  3. 创建MyRunable类的对象myRunable
  4. 创建Thread类的对象,且将myRunable对象作构造方法的参数传递
  5. 启动线程 . start方法

问题:为什么有了方法1,还需要方法2

  1. 为了避免 java 中由于单继承带来的局限性
  2. runable接口实现的线程,适合多个相同的代码去处理同一个资源的情况,把线程的同程序的代码,数据进行有效分享(资源共享),体现了面向对象思想

线程安全问题

案例:卖票????

出现同票原因

// 分析同票的原因
// 线程抢夺cpu 执行权时,执行的代码具有原子性
// 原子性是指最基本的代码(最小的语句)

出现负票的原因???

如何解决

什么情况会出现线程安全问题

  1. 是否多线程环境
  2. 是否有共享资源
  3. 是否有多条语句操作共享资源

同步锁

同步代码块

锁对象:任意对象

语法:

synchronized (obj){//操作共享数据的代码}
同步方法

同步方法的锁对象是this

public synchronized void sellTicket(){if(ticket>0){ // c1  c2  c3  ticket = 1try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"第"+ticket+"张票");ticket--;// 0}
}
同步静态方法

同步方法的锁对象是当前类的字节码对象(反射会学习)

public synchronized  static void sellTicket(){if(ticket>0){ // c1  c2  c3  ticket = 1try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"第"+ticket+"张票");ticket--;// 0}
}
Lock锁
public void run() {while (true){lock.lock(); //上锁if(ticket>0){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"第"+ticket+"张票");ticket--;// 0}lock.unlock(); //释放锁}}
synchronized与lock的区别
  • synchronized:jvm级别的锁,jvm自动上锁和解锁
  • lock锁:java代码的锁,需要手动的加锁和释放锁
死锁

多线程产生死锁的四个必要条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 保持和请求条件:一个进程因请求资源而阻塞时,对已获得资源保持不妨。
  • 不可剥夺调用:进程已获得资源,在未使用完成前,不能被剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
public class MyThread extends Thread{private boolean flag;public MyThread(Boolean flag){this.flag = flag;}@Overridepublic void run() {if(flag){synchronized (LockObject.objA) { //try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("我有锁A,需要锁B");synchronized (LockObject.objB) {System.out.println(Thread.currentThread().getName() + ":我有锁B");}}}else{synchronized (LockObject.objB) { //try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("我有锁A,需要锁B");synchronized (LockObject.objA) {System.out.println(Thread.currentThread().getName() + ":我有锁B");}}}}
}
public class LockObject {public static Object objA = new Object();public static Object objB = new Object();
}
public class Example02 {public static void main(String[] args) {MyThread thread = new MyThread(true);MyThread thread2 = new MyThread(false);thread.start();thread2.start();}
}

十、线程的生命周期

线程的生命周期(状态):

  • 新建:创建一个线程对象
  • 就绪:对象调用start()方法,有执行资格,但是没有抢到CPU资源
  • 运行:抢到了CPU资源,有执行权
  • 阻塞:通过sleep(),wait()等方法让线程中断运行,没有了执行资格
  • 死亡:线程执行完毕,等待垃圾回收

在这里插入图片描述

十一、线程之间的通信

生产者:

​ 先查看是否有资源,有就等待,没有就生产,生产后通知消费者来消费资源

消费者:

​ 先查看是否有资源,有就消费资源,没有就通知生产者生产资源并等待

在这里插入图片描述

public class BaoZi { // 公共资源包子类public String name;public boolean flag=false; //是否有资源public BaoZi(){}public String getName() {return name;}public void setName(String name) {this.name = name;}public BaoZi(String name){this.name = name;}
}// 生产者,包包子的
public class SetBaoZi extends Thread{ private BaoZi bz;private int x = 0;public SetBaoZi(BaoZi bz){this.bz = bz;}@Overridepublic void run() {while (true){synchronized (bz){if (bz.flag){ // 有资源,不需要包包子,等待资源消耗完try{bz.wait();} catch (InterruptedException e){throw new RuntimeException(e);}}if (x%2==0){bz.name = "小笼包";}else {bz.name = "酱肉包";}bz.notify(); // 唤醒消费者线程bz.flag = true;x++;}}}
}// 消费者
public class GetBaoZi extends Thread{private BaoZi bz;public GetBaoZi(BaoZi bz) {this.bz = bz;}@Overridepublic void run() {while (true){synchronized (bz){if (!bz.flag){try {bz.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("消费了包子:"+bz.name);bz.flag = false;bz.notify(); // 包子被消费,唤醒生产者线程包包子}}}
}// 测试
public class Test {public static void main(String[] args) {BaoZi baoZi = new BaoZi();SetBaoZi setBaoZi = new SetBaoZi(baoZi);GetBaoZi getBaoZi = new GetBaoZi(baoZi);setBaoZi.start();getBaoZi.start();}
}// 加锁,解决了消费资源出错的问题
// 使用wait和notify解决了多次消费同一资源的问题
线程间通信的内存图

常见情况:

  1. 新建 – 就绪 – 运行 – 死亡
  2. 新建 – 就绪 – 运行 – 就绪 – 运行 – 死亡
  3. 新建 – 就绪 – 运行 – 等待阻塞 – 同步阻塞 – 就绪 – 运行–死亡
  4. 新建 – 就绪 – 运行 – 其它阻塞 – 就绪 – 运行–死亡
  5. 新建 – 就绪 – 运行 – 同步阻塞 – 就绪 – 运行–死亡

在这里插入图片描述

十二、线程池

使用线程池的思想,池化思想可以提高重用性和效率(Executors)。

class MyCallable implements Callable {@Overridepublic Object call() throws Exception {System.out.println("我是callable方法");return null;}
}
public class Example01 {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(2);MyCallable myCallable1 = new MyCallable();MyCallable myCallable2 = new MyCallable();service.submit(myCallable1);service.submit(myCallable2);}
}

十二、线程池

使用线程池的思想,池化思想可以提高重用性和效率(Executors)。

class MyCallable implements Callable {@Overridepublic Object call() throws Exception {System.out.println("我是callable方法");return null;}
}
public class Example01 {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(2);MyCallable myCallable1 = new MyCallable();MyCallable myCallable2 = new MyCallable();service.submit(myCallable1);service.submit(myCallable2);}
}

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

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

相关文章

Argon-Theme 轻盈、简洁、美观的 WordPress 主题-供大家学习研究参考

特性 轻盈美观 - 使用 Argon Design System 前端框架,细节精致,轻盈美观高度可定制化 - 可自定义主题色、布局(双栏/单栏/三栏)、顶栏、侧栏、Banner、背景图、日夜间模式不同背景、背景沉浸、浮动操作按钮等,提供了丰富的自定义选项夜间模式 - 支持日间、夜间、纯黑三种模式…

力扣每日一题----2008. 出租车的最大盈利

这题我们是怎么思考的呢&#xff1f; 已知有乘客最多30000个&#xff0c;有最多100000个地点&#xff0c;那么通过算法时间复杂度&#xff0c;不可能是O(n^2), 那么我们就可以去看题目&#xff0c;题目又是最多盈利多少元&#xff1f;那么很容易联想到动态规划&#xff0c;并…

湖南大学-电路与电子学-2021期末A卷★(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程&#xff0c;故实际上目前只有2020与2021两个年级考过期末考试。 本份卷子的参考性很高&#xff0c;这是2020级的期末考卷。题目都是很典型的&#xff0c;每一道题都值得仔细研究透。 特别注意&#xff1a;看得懂答案跟写得…

Linux学习笔记之八(进程间的共享内存)

Linux 1、引言2、实现共享内存2.1、创建一个共享内存2.2、将共享内存链接到进程空间2.3、断开与共享内存的链接2.4、对共享内存进行后续操作 3、应用实例 1、引言 在之前一篇文章Linux学习笔记之六&#xff08;进程之间的管道通信和信号处理&#xff09;中我讲了进程间可以通过…

sql 读写注入

root高权限读写注入 load_file 读取文件 大姐我真是整了半天都是nullnullnull缝子 结果看了半天这个my.ini是被隐藏的大哥 load_file()读取文件结果为null_mysql load_file返回null解决办法_黑小薛的博客-CSDN博客 终于读出来了 此时参数值系统变量 secure_file_priv已经被修…

Redis缓存如何设置时间?

在Redis中&#xff0c;你可以使用SET命令设置缓存&#xff0c;并使用EXPIRE命令设置key的过期时间。以下是一些基本的使用方法 设置缓存值 使用SET命令可以设置缓存值 SET key_name "your_value"这将在Redis中创建一个键为key_name&#xff0c;值为"your_val…

三天精通Selenium Web 自动化 - 项目实战环境准备

1 部署TestNG 返回 TestNG&#xff0c;即Testing Next Generation&#xff0c;下一代测试技术&#xff0c;是一套根据JUnit和NUnit思想而构建的利用注释来强化测试功能的一个测试框架&#xff0c;即可以用来做单元测试&#xff0c;也可以用来做集成测试。更多细节可以到官网去…

MacBook充不了电问题可大可小,但大部分通过简单的排除就可以解决

如果你的MacBook Pro或MacBook Air无法充电&#xff0c;或者充电器不工作&#xff0c;那么随着电池电量的耗尽&#xff0c;让其正常工作可能是在与时间赛跑。在这篇文章中&#xff0c;我们将了解Mac笔记本电脑可能无法充电的可能原因&#xff0c;以及如何修复。 我们还将研究如…

钩不了判断

直言命题 第一种&#xff1a;直言命题&#xff08;<3种元素&#xff09; 所有&#xff08;指所有&#xff1b;范围小&#xff09; 某个&#xff08;特指一个&#xff1b;范围小&#xff09; 有的、有些&#xff08;可以指一个、一部分、所有&#xff1b;范围大&#xff09;…

Java实现插入排序及其动图演示

插入排序是一种简单直观的排序算法。它的基本思想是将一个待排序的元素插入到已经排序好的序列中的适当位置&#xff0c;从而得到一个新的、元素个数加一的有序序列。 具体的插入排序算法过程如下&#xff1a; 从第一个元素开始&#xff0c;认为第一个元素已经是有序序列。取…

git常规操作流程(纯命令行操作)和一些注意事项

当你在单位拿到了git仓库,并利用公司给你的OA账号和邮箱完成了你的git基础配置,下面就是使用命令行的无错固定操作流程 如果你很着急,你可以直接跳到最后的总结部分 具体步骤 1.从仓库克隆代码到本地 这里的[codeUrl]就是你仓库的地址,当你在仓库点击图中绿色位置时,剪贴板…

SpringCloud+Consul快速开发示例

简介 本章通过最新的springcloud版本与官方最新consul开源版服务&#xff0c;进行演示&#xff0c;如何快速搭建开发环境和注册与发现服务中心&#xff1b; 本文假设已知具备SpringCloud的基础开发能力&#xff0c;以及提前了解consul服务的使用&#xff0c;因此本文不会详细…

孩子还是有一颗网安梦——Bandit通关教程:Level 9 → Level 10

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

网络基础(八):路由器的基本原理及配置

目录 1、路由概述 2、路由器 2.1路由器的工作原理 2.2路由器的转发原理 3、路由表 3.1路由表的概述 3.2路由表的形成 4、静态路由配置过程&#xff08;使用eNSP软件配置&#xff09; 4.1两个静态路由器配置过程 4.2三个静态路由器配置过程 5、默认路由配置过程 5.…

Qt 容器QGroupBox带有标题的组框框架

控件简介 QGroupBox 小部件提供一个带有标题的组框框架。一般与一组或者是同类型的部件一起使用。教你会用,怎么用的强大就靠你了靓仔、靓妹。 用法示例 例 qgroupbox,组框示例(难度:简单),使用 3 个 QRadioButton 单选框按钮,与QVBoxLayout(垂直布局)来展示组框的…

若依框架启动过程中遇到的控制台使用npm i下载相关依赖报错的问题以及前端启动遇到的问题

目录 报错截图问题解决其他问题 npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。问题解决更改环境变量新建系统变量 其他问题 错误解决Error: error:0…

美食大赛的题解

目录 原题描述&#xff1a; 题目描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 样例输入&#xff1a; 样例输出&#xff1a; 数据规模&#xff1a; 题目大意&#xff1a; 主要思路&#xff1a; 注&#xff1a; 代码&#xff1a; 原题描述&#xff1a…

Uniapp软件库全新带勋章功能(包含前后端源码)

源码介绍&#xff1a; Uniapp开发的软件库全新带勋章功能&#xff0c;搭建好后台 在前端找到 util 这个文件 把两个js文件上面的填上自己的域名&#xff0c;电脑需要下载&#xff1a;HBuilderX 登录账号 没有账号就注册账号&#xff0c; 然后上传文件&#xff0c;打包选择 “…

js 有关递归简单介绍

递归&#xff1a;指调用自身的函数 重点&#xff1a;递归函数必须有可以终止递归调用的语句&#xff0c;否则会导致内存溢出 递归的性能不好&#xff0c;因为在递归终止前&#xff0c;JavaScript引擎会为每一次递归分配一块内存以存储栈帧&#xff0c;随着递归的深入&#xff…

基于双树复小波变换和稀疏表示的多光谱和彩色图像融合算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 双树复小波变换原理 4.2 稀疏表示原理 4.3 基于双树复小波变换和稀疏表示的图像融合算法 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序…