当前位置: 首页 > news >正文

(二十)Java之多线程

目录

1.多线程

2.并发和并行

3.多线程的实现方式

4.Thread类常见成员方法

5.线程的生命周期

​编辑6.线程安全问题(同步代码块)

7.同步方法

8.Lock锁​编辑

9.等待唤醒机制

10.多线程代码思路

11.阻塞队列

12.多线程的六大状态


1.多线程

进程:进程是程序的基本执行实体,可以理解为计算机每开一个软件都是一个进程

线程:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

可以把线程简单理解为应用软件中互相独立,可以同时运行的功能

问题1.什么是多线程?
有了多线程,我们就可以让程序同时做多件事情
问题2.多线程的作用?
提高效率
问题3.多线程的应用场景?
只要你想让多个事情同时运行就需要用到多线程,比如:软件中的耗时操作、所有的聊天软件、所有的服务器

2.并发和并行

并发:在同一时刻,有多个指令在单个CPU上交替执行
并行:在同一时刻,有多个指令在多个CPU上同时执行

疑问:电脑CPU不是只有一颗吗?对的,但是CPU分为2核4线程、4核8线程、8核16线程、16核32线程、32核64线程...

3.多线程的实现方式

  • 继承Thread类的方式进行实现
  • 实现Runnable接口的方式进行实现
  • 利用Callable接口和Future接口方式实现
方法1:继承Thread类的方式进行实现
public class MyThread extends Thread{@Overridepublic void run() {
//书写线程要执行的代码for (int i = 0; i < 10; i++) {System.out.println(this.getName() + "Hello MyThread");}}
}public class ThreadDemo1{public static void main(String[] args) {MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();myThread1.setName("线程1:");myThread2.setName("线程2:");myThread1.start();myThread2.start();}
}
输出结果:交替随机
线程1:Hello MyThread
线程2:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程1:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
线程2:Hello MyThread
线程1:Hello MyThread
方法2:实现Runnable接口的方式进行实现
public class MyRun implements Runnable{@Overridepublic void run() {for (int i = 0; i < 10; i++) {//获取当前线程的对象,因为此时本类没有继承Thread类//所以不能调用getname()方法System.out.println(Thread.currentThread().getName() + "Hello Thread");}}
}public class ThreadDemo2 {public static void main(String[] args) {MyRun mr = new MyRun();Thread thread1 = new Thread(mr);Thread thread2 = new Thread(mr);thread1.setName("线程1:");thread2.setName("线程2:");thread1.start();thread2.start();}
}

无论是第一种继承Thread类还是第二种实现Runnable接口,其中的方法run()的返回值都是void,所以如果想要得到线程运行的结果就需要用到第三种方法

多线程的第三种实现方式:
特点:可以获取到多线程运行的结果

  1. 创建一个类MyCallable实现callable接口
  2. 重写call() (是有返回值的,表示多线程运行的结果)
  3. 创建MyCallable的对象(表示多线程要执行的任务) 
  4. 创建FutureTask的对象(作用管理多线程运行的结果)
  5. 创建Thread类的对象,并启动(表示线程)
方法3:利用Callable接口和Future接口方式实现
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {//求1~100的和int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}return sum;}
}public class ThreadDemo3{public static void main(String[] args) throws ExecutionException, InterruptedException {//创建MyCallable的对象(表示多线程要执行的任务)MyCallable mc = new MyCallable();//创建FutureTask的对象(作用管理多线程运行的结果)FutureTask<Integer> ft = new FutureTask<>(mc);//创建线程的对象Thread t1 = new Thread(ft);//启动线程t1.start();//获取多线程运行的结果Integer result=ft.get();System.out.println(result);}
}

4.Thread类常见成员方法

 细节1:如果我们没有给线程设置名字,线程也是有默认的名字的,格式:Thread-x(X序号,从0开始的),比如实例化的第一个线程为Thread-0

细节2:用构造方法设置姓名时,需要继承Thread的对象类重写构造方法,因为构造方法不能继承

细节3:当JVM虚拟机启动之后,会自动的启动多条线程其中,有一条线程就叫做main线程,他的作用就是去调用main方法,并执行里面的代码,我们写的所有的代码其实都是运行在main线程当中

细节4:线程的调度分为抢占式调度(随机)和非抢占式调度,Java中采用的是抢占式,线程优先级1~10十档,默认为5

细节5:final void setDaemon(Boolean on)方法设置为守护线程,当其他的非守护线程执行完毕之后,守线程会陆续结束,相当于是“备胎”,使用场景:聊天框和发送图片,当把聊天框这个线程结束以后,发送图片就没有必要继续执行下去了,执行一段时间可以自动关闭

细节6:出让/礼让线程,Thread.yield(),让线程的执行尽可能均匀,让出当前CPU的执行权

细节7:插入线程join()方法,表示把方法调用者这个线程,插入到当前线程之前

5.线程的生命周期

6.线程安全问题(同步代码块)

案例:多线程卖票,某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

首先要知道一个前提,线程在执行任务的时候,CPU的执行权可能随时会被抢走,所以如果实例化三个对象执行同一段代码就有可能出现第一个对象还没执行到打印语句就被抢走了执行权,那么最简单的想法就是把需要执行的代码“锁起来”,从而引出了——同步代码块,作用:把操作共享数据的代码锁起来

public class MyThread extends Thread{表示这个类所有的对象,都共享ticket数据static int ticket = 1;锁对象一定要是唯一的static Object obj = new Object();@Overridepublic void run() {while (true){synchronized (obj){if(ticket <= 100){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(this.getName() + "正在售卖第" + ticket);ticket++;}else {break;}}}}
}public class ThreadDemo1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("售票窗口1");t2.setName("售票窗口2");t3.setName("售票窗口3");t1.start();t2.start();t3.start();}
}

7.同步方法

StringBuilder用于单线程情况下,不需要考虑数据安全

StringBuffer用于多线程情况下

8.Lock锁

9.等待唤醒机制

思路分析:此处消费者和生产者的等待和唤醒操作就是机制的原理

10.多线程代码思路

  1. 循环(while true)
  2. 同步代码块synchronized
  3. 判断共享数据是否到了末尾(到了末尾,if...break)
  4. 判断共享数据是否到了末尾(没有到末尾,执行核心逻辑else)

11.阻塞队列

12.多线程的六大状态

在Java虚拟机中没有定义运行状态

线程的状态操作
新建状态(NEW)创建线程对象
就绪状态(RUNNABLE)start()
阻塞状态(BLOCKED)无法获得锁对象
等待状态(WAITING)wait()
计时等待(TIMED WAITING)sleep()
结束状态(TERMINATED)全部代码运行完毕

http://www.mrgr.cn/news/56725.html

相关文章:

  • 企业数字化转型的理论指南:构建未来企业的关键策略与实践路径
  • Linux-shell实例手册-服务操作
  • 原生页面引入Webpack打包JS
  • JavaSE——IO流5:高级流(序列化与反序列化流/对象操作流)
  • C# 迭代器 分部类
  • 市场洞察:看机会的底层逻辑
  • 浅谈人工智能之基于阿里云使用vllm搭建Llama3
  • Acti数据集:首个全面手动标注的汽车网络安全威胁情报语料库,包含908份真实报告,涵盖3678个句子、8195个安全实体和4852个语义关系。
  • torch.nn.functional模块介绍
  • 推荐一款风扇控制软件:Fan Control
  • C++与现代开发实践第二课:C++标准库(STL)深入
  • 【C#】不需要连接数据库使用 ADO.NET 实现数据绑定
  • 人工智能--数学基础
  • AIGC文本生成3D模型
  • 模型的参数化和非参数化是什么?
  • 常见的css选择器汇总
  • 管家婆ERP集成用友好业财(管家婆主供应链)
  • 机器视觉运动控制一体机在DELTA并联机械手视觉上下料应用
  • HBuilderX离线打包Android
  • 会话管理——Cookie