Java多线程详解
2021/7/15 9:06:26
本文主要是介绍Java多线程详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、区分多任务与多线程
多任务 : 同一时间处理多个任务
多线程 : 相当于开设了 多条通道,提高了CPU使用的效率
-
例子: 多个人同时登陆游戏
主线程-main方法 和 其他方法-子线程 同时运行
-
普通方法调用:
-
特点:只有主线程一条执行路径
-
-
多线程:
-
特点:多条执行路径,主线程和子线程并行交替执行
二、区分程序、进程、线程
进程 Process:
-
在OS中运行的程序=>进程 e.g.QQ 播放器 游戏...
-
一个进程可以有多个线程!如同时听声音、看图像、看弹幕...
-
进程是执行程序的一次执行过程,动态的,
-
系统资源分配的单位
-
一个进程包含至少一个线程
线程 Thread :
- CPU调度和执行的单位(CPU时间片)
- 独立的执行路径
- main()称为主线程,作为系统的入口,用于执行整个程序
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程、gc线程
- 多线程情况下,线程的运行需要调度器(CPU)安排调度,先后顺序无法人为干预!
- 对同一份资源操作时,会出现资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销:CPU调度时间+并发控制开销
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致!
三、线程创建的方式
主要有三种 :Thread、Runnable、Callable
Thread => class 继承Thread类
Runnable => 接口 实现Runnable接口
Callable => 接口 实现Callable接口 (了解)
main() : 用户线程
gc线程: 守护线程
开启线程的方法:
-
1、Thread
- 自定义线程类 继承 (extends)Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法!
注意:线程不一定立即执行,而是由CPU安排调度
不建议使用:避免OOP单继承局限性
-
2、实现Runnable接口
-
定义MyRunnable类实现Runnable接口
-
实现run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动线程
- 推荐使用Runnable对象,因为Java单继承的局限性(接口可以多次实现) 灵活方便,方便同一个对象被对多个线程使用
public class StartThread implements Runnable{ @Override public void run(){ // 线程体 for(int i = 0; i <20; i++){ System.out.println("我在学习Java多线程!"); } } public static void main(String[] args){ // 创建实现类对象 StartThread st = new StartThread(); // 创建代理类对象 Thread thread = new Thread(st); // 启动线程 thread.start(); } }
-
3、实现Callable接口 (了解)
(1). 实现Callable接口,需要返回值类型(Boolean String....) 相当于返回一条消息
(2). 重写call方法,需要抛出异常
(3). 创建目标对象
(4). 创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(1);
(5). 提交执行
Future<Boolean>result1 = ser.submit(t1);
(6). 获取结果
boolean r1 = result1.get();
(7). 关闭服务
ser.shutdownNow();
静态代理? vs Thread
即 Static Proxy
静态代理模式:
- 真实对象和代理对象都要实现同一个接口
- 代理对象要 代理 真实对象,即
// 静态代理 You ==>真实对象 WeddingCompany代理对象 WeddingCompany weddingCompany = new WeddingCompany(new You()); weddingCompany.marry(); new WeddingCompany(new You()).marry();
new Thread(()-> System.out.println("这里是目标对象!")).start();
好处:
- 代理对象可以做很多真实对象做不了的事情
- 真实对象可以专注做自己的事情
lambda表达式
-
λ 希腊字母表中排序第十一位的字母,英文名称为Lambda
-
作用:避免匿名内部类定义过多
-
实质:函数式编程
new Thread(()-> System.out.println("多线程学习中!"));
(params) -> expression [表达式] or
(params) -> statement[语句] or
(params) -> { statements}
为什么要使用Lambda表达式?
- 避免匿名内部类定义过多
- 让代码看起来很简洁
- 去掉没有意义的代码,只留下核心逻辑
函数式接口 ?
即 Functional Interface
- Java8 更新了lambda表达式
定义:
-
任何接口,如果只包含唯一一个抽象方法,即为一个函数式接口
-
对于函数式接口。可以通过Lambda表达式来创建该接口!
public interface Runnable { public abstract void run(); }
总结:
-
lambda表达式只能在只有一行代码的情况下才能简化成为一行
如果有多行代码,需要用代码块包裹(前提:接口为函数式接口且只有一个)
-
lambda表达式中的多个参数也可以去掉参数类型,要去掉就全部去掉,多个参数需要用括号包起来
-
线程状态 (五大状态)
- 创建状态
- 就绪状态
- 阻塞状态
- 运行状态
- 死亡状态
创建状态 -- 启动线程 --> 就绪状态
阻塞状态 -- 阻塞解除 --> 就绪状态
就绪状态 --获得CPU资源 --> 运行状态
就绪状态 <--释放CPU资源 -- 运行状态
运行状态 -- 等待用户输入/线程休眠--> 阻塞状态
运行状态 --线程自然执行完毕/外部干涉终止线程--> 死亡状态
线程常用方法:
- setPriority(int newPriority) 更改线程的优先级
- static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
- void join() 等待该线程终止(新线程此时无法进入就绪状态)
- static void yield() 暂停当前正在执行的线程对象,并执行其他线程
- void interrupt() 中断线程,不推荐使用
- boolean isAlive() 测试线程是否处于活动状态
停止线程
-
不推荐使用JDK提供的stop()、destory()方法 --> 已废弃
-
推荐让线程自己停止下来
-
建议使用一个标志位作为终止变量
当flag = false 则终止线程运行
这篇关于Java多线程详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-05并查集详解与实现教程
- 2024-11-05大厂数据结构与算法入门指南
- 2024-11-05大厂算法与数据结构入门指南
- 2024-11-05二叉树入门教程:轻松掌握基础概念与操作
- 2024-11-05红黑树入门教程:从零开始理解红黑树
- 2024-11-05初学者必备:链表基础知识详解
- 2024-11-05平衡树入门教程:理解、构建与应用
- 2024-11-05数据结构入门教程:轻松掌握基础知识
- 2024-11-05数据结构与算法入门教程
- 2024-11-05优先队列入门教程:理解与实现