网站首页 > 技术教程 正文
多线程是什么?为什么要用多线程?
介绍多线程之前要介绍线程,介绍线程则离不开进程。
首先 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元;
线程:就是进程中的一个独立控制单元,线程在控制着进程的执行。一个进程中至少有一个进程。
多线程:一个进程中不只有一个线程。
为什么要用多线程:
①、为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;
②、进程之间不能共享数据,线程可以;
③、系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;
④、Java语言内置了多线程功能支持,简化了java多线程编程。
二、线程的生命周期:
新建 :从新建一个线程对象到程序start() 这个线程之间的状态,都是新建状态;
就绪 :线程对象调用start()方法后,就处于就绪状态,等到JVM里的线程调度器的调度;
运行 :就绪状态下的线程在获取CPU资源后就可以执行run(),此时的线程便处于运行状态,运行状态的线程可变为就绪、阻塞及死亡三种状态。
等待/阻塞/睡眠 :在一个线程执行了sleep(睡眠)、suspend(挂起)等方法后会失去所占有的资源,从而进入阻塞状态,在睡眠结束后可重新进入就绪状态。
终止 :run()方法完成后或发生其他终止条件时就会切换到终止状态。
三、创建线程的方法:具体实现代码详解请看点击后方链接:多线程扩展一、创建线程的三种方法详细对比(http://www.cnblogs.com/yjboke/p/8919090.html)
1、继承Thread类:
步骤:①、定义类继承Thread;
②、复写Thread类中的run方法;
目的:将自定义代码存储在run方法,让线程运行
③、调用线程的start方法:
该方法有两步:启动线程,调用run方法。
2、实现Runnable接口: 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。
实现步骤: ①、定义类实现Runnable接口
②、覆盖Runnable接口中的run方法
将线程要运行的代码放在该run方法中。
③、通过Thread类建立线程对象。
④、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程执行指定对象的run方法就要先明确run方法所属对象
⑤、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
3、通过Callable和Future创建线程:
实现步骤:①、创建Callable接口的实现类,并实现call()方法,改方法将作为线程执行体,且具有返回值。
②、创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
③、使用FutureTask对象作为Thread对象启动新线程。
④、调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
四、继承Thread类和实现Runnable接口、实现Callable接口的区别。
继承Thread:线程代码存放在Thread子类run方法中。
优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
劣势:已经继承了Thread类,无法再继承其他类。
实现Runnable:线程代码存放在接口的子类的run方法中。
优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。
实现Callable:
优势:有返回值、避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法
建议使用实现接口的方式创建多线程。
五、线程状态管理
1、线程睡眠---sleep:
线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程。
线程睡眠的方法(两个):sleep(long millis)在指定的毫秒数内让正在执行的线程休眠。
sleep(long millis,int nanos)在指定的毫秒数加指定的纳秒数内让正在执行的线程休眠。
线程睡眠的代码演示:
public class SynTest { public static void main(String[] args) { new Thread(new CountDown(),"倒计时").start(); } }class CountDown implements Runnable{ int time = 10; public void run() { while (true) { if(time>=0){ System.out.println(Thread.currentThread().getName() + ":" + time--); try { Thread.sleep(1000); //睡眠时间为1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } }
每隔一秒则会打印一次,打印结果为:
倒计时:10倒计时:9倒计时:8倒计时:7倒计时:6倒计时:5倒计时:4倒计时:3倒计时:2倒计时:1倒计时:0
扩展:Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。但是不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而不能做到精准控制。因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒。
2、线程让步---yield:
该方法和sleep方法类似,也是Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态。
public class SynTest { public static void main(String[] args) { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms,"张三吃完还剩"); Thread t2 = new Thread(ms,"李四吃完还剩"); Thread t3 = new Thread(ms,"王五吃完还剩"); t1.start(); t2.start(); t3.start(); } }class yieldDemo implements Runnable{ int count = 20; public void run() { while (true) { if(count>0){ System.out.println(Thread.currentThread().getName() + count-- + "个瓜"); if(count % 2 == 0){ Thread.yield(); //线程让步 } } } } }
sleep和yield的区别:
①、sleep方法声明抛出InterruptedException,调用该方法需要捕获该异常。yield没有声明异常,也无需捕获。
②、sleep方法暂停当前线程后,会进入阻塞状态,只有当睡眠时间到了,才会转入就绪状态。而yield方法调用后 ,是直接进入就绪状态。
3、线程合并---join:
当B线程执行到了A线程的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行。
join可以用来临时加入线程执行。
以下为代码演示:
public static void main(String[] args) throws InterruptedException { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms,"张三吃完还剩"); Thread t2 = new Thread(ms,"李四吃完还剩"); Thread t3 = new Thread(ms,"王五吃完还剩"); t1.start(); t1.join(); t2.start(); t3.start(); System.out.println( "主线程"); }
4、停止线程:
原stop方法因有缺陷已经停用了,那么现在改如何停止线程?现在分享一种,就是让run方法结束。
开启多线程运行,运行的代码通常是循环结构,只要控制住循环,就可以让run方法结束
猜你喜欢
- 2024-11-06 Qt音视频开发9-ffmpeg录像存储(nba比赛录像回放)
- 2024-11-06 音视频开源基础 - ffmpeg命令(ffmpeg音频处理)
- 2024-11-06 ffmpeg常用命令行集锦(ffmpeg 命令大全)
- 2024-11-06 音视频开发7. ffmpeg 几个重要结构体
- 2024-11-06 超详细的手把手下载安装FFmpeg整个过程,你学会了吗?
- 2024-11-06 FFmpeg硬解码(ffmpeg硬解码和直接使用cuda的区别)
- 2024-11-06 mPEG-Lys(MAL)-DBCO,甲氧基PEG赖氨酸马来酰亚胺二苯并环辛炔
- 2024-11-06 音视频流媒体高级开发(FFmpeg6.0/WebRTC/RTMP/RTSP/编码解码)
- 2024-11-06 FFmpeg在windows的安装、合并、切片、.m4s、.m3u8处理
- 2024-11-06 完美解决Linux环境编译ffmpeg库(linux编译环境配置)
你 发表评论:
欢迎- 最近发表
-
- Win11学院:如何在Windows 11上使用WSL安装Ubuntu
- linux移植(Linux移植freemodbus)
- 独家解读:Win10预览版9879为何无法识别硬盘
- 基于Linux系统的本地Yum源搭建与配置(ISO方式、RPM方式)
- Docker镜像瘦身(docker 减小镜像大小)
- 在linux上安装ollama(linux安装locale)
- 渗透测试系统Kali推出Docker镜像(kali linux渗透测试技术详解pdf)
- Linux环境中部署Harbor私有镜像仓库
- linux之间传文件命令之Rsync傻瓜式教程
- 解决ollama在linux中安装或升级时,通过国内镜像缩短安装时长
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)