藏好自己,做好清理
实际上是多个CPU,即多核,如果一个CPU情况下,其实是一个时刻处理一个线程,一段时间内处理多个线程
1. 进程与线程
进程是程序的一次动态执行过程,它经历了从代码加载(产生)、执行(发展)到执行完毕(消亡)的一个完整过程。每个进程都能循环获得自己的CPU时间片,CPU执行速度非常快,所以好像同时运行一样。
1.1 打开WPS是打开一个程序,也相当于启动了一个进程,WPS的拼音检查就是一个线程,可以有很多的线程在进程上,PID的P就是Process【进程】
1.2 在一个进程中,自己没有创建线程,后台也会有多个线程,如main()【主线程】,gc线程【垃圾回收线程】
1.3 单线程:run()方法先执行完再返回到主方法
1.4 多线程:start()方法和主方法一起并发执行(时间段);在时刻上还是执行其中一个
2. 多线程实现
2.1 继承Thread类(java.lang.Thread)
- 栗子1:
1 | //创建线程方式一:继承Thread类,重写run方法,调用start开启线程 |
- 栗子2:下载多张图片
1 | package com.xxy.thread; |
- 为什么线程启动必须调用start()方法执行而不是直接调用run()方法
start()方法源码:
1 | public synchronized void start() { |
1 | private native void start0(); |
为了java的可移植性,只在意调用操作系统的函数功能来实现start0()方法
- 缺点
单继承局限
2.2 实现Runnable接口
避免了单继承的局限性
- Runnable接口源码
1 | // |
- 栗子1:
1 | package com.xxy.thread; |
- 栗子2:lambda表达式,jdk1.8新特性
1 | package com.xxy.thread; |
- 栗子3:多线程下载图片
1 | package com.xxy.test; |
- 栗子4:并发问题
1 | package com.xxy.thread; |
- 栗子5:龟兔赛跑
1 | package com.xxy.thread; |
2.3 实现Callable接口
可以有返回值,有call()方法,需要抛出异常
- Callable接口源码
1 | // |
- 栗子:
1 | package com.xxy.thread; |
3. 多线程操作方法
3.1 多线程运行状态
注意:线程开启不一定立即执行,有可能为就绪状态,由cpu调度执行
1 | graph LR |
- 栗子
1 | package com.xxy.thread; |
3.2 操作方法
方法 | 类型 | 说明 |
---|---|---|
public Thread(Runnable var1, String var2) | 构造 | 实例化线程对象,接收Runnable接口子类对象,同时设置线程名字 |
public final synchronized void setName(String var1) | 普通 | 设置线程名字 |
public final String getName() | 普通 | 取得线程名字 |
public static native Thread currentThread() | 普通 | 获取当前线程对象 |
4. 线程休眠(sleep())
每一个对象都有一个锁,sleep不会释放锁
方法 | 类型 | 说明 |
---|---|---|
public static native void sleep(long var0) throws InterruptedException | 普通 | 设置线程休眠的毫秒数,时间一到自动唤醒 |
public static void sleep(long var0, int var2) throws InterruptedException | 普通 | 设置线程休眠的毫秒数与纳秒数,时间一到自动唤醒 |
5. 线程中断(interrupt())
一般不会使用此方法中断线程
方法 | 类型 | 说明 |
---|---|---|
public boolean isInterrupted() | 普通 | 判断线程是否被中断 |
public void interrupt() | 普通 | 中断线程执行,别用这个方式 |
public final native boolean isAlive() | 普通 | 测试线程是否处于活动状态 |
6. 线程强制执行(join())
方法 | 类型 | 说明 |
---|---|---|
public final void join() throws InterruptedException | 普通 | 可以强制执行,等它执行后其他线程再执行 |
- 栗子
1 | package com.xxy.thread; |
7. 线程礼让(yield())
让cpu重新调度,不一定礼让成功
方法 | 类型 | 说明 |
---|---|---|
public static native void yield() | 普通 | 线程礼让 |
- 栗子
1 | package com.xxy.thread; |
8. 线程优先级(setPriority())
优先级低意味着获得CPU调度的概率低,并不是不会调用,有可能优先级低在优先级高的前面调用
方法 | 类型 | 说明 |
---|---|---|
public static final int MIN_PRIORITY = 1 | 常量 | 最高优先级,数值为10 |
public static final int NORM_PRIORITY = 5 | 常量 | 中等优先级,数值为5 |
public static final int MAX_PRIORITY = 10 | 常量 | 最低优先级,数值为1 |
public final void setPriority(int var1) | 普通 | 设置线程优先级 |
public final int getPriority() | 普通 | 取得线程优先级 |
- 栗子
1 | package com.xxy.thread; |
9. 同步与死锁(synchronized、lock)
9.1 同步
多个线程操作同一个资源,队列+锁来实现
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
9.2 同步不安全栗子
9.3 synchronized锁(本质还是队列+隐式锁)
出了作用域自动释放
锁方法
栗子1:
1 | package com.xxy.syc; |
- 锁代码块
- 栗子1:
1 | package com.xxy.syc; |
- 栗子二:
1 | package com.xxy.syc; |
- 栗子3;JUC安全类型集合
1 | package com.xxy.syc; |
缺陷:将一个大的方法声明为synchronized,将会极大影响性能
9.4 死锁
两个或多个线程各自等待对方的资源或释放资源,都处于等待的情况
1 | package com.xxy.syc; |
- 显示定义同步锁(Lock)
java.util.concurrent.lock接口控制多个线程对共享资源进行访问
只有代码块锁,性能比隐式锁更好,需要自己释放锁
- 栗子
1 | package com.xxy.syc; |
10. 停止线程
stop()、suspend()、resume()在jdk1.2已经不再使用,wait(),notify()属于Object类,不属于Thread类,推荐线程自己停止下来,或者标志位
方法 | 类型 | 说明 |
---|---|---|
private native void stop0(Object var1) | 普通 | 停止多线程 |
private native void suspend0() | 普通 | 挂起线程、暂停执行 |
private native void resume0() | 普通 | 恢复挂起的线程执行 |
注意:都是Object类停止或唤醒线程,只能在同步方法或者同步代码块中使用,否则抛出异常
方法 | 类型 | 说明 |
---|---|---|
public final void wait() throws InterruptedException | 普通 | 线程的等待 |
public final native void wait(long var1) throws InterruptedException | 普通 | 设置线程等待的毫秒数 |
public final void wait(long var1, int var3) throws InterruptedException | 普通 | 设置线程等待的毫秒数和纳秒数 |
public final native void notify() | 普通 | 唤醒第一个等待的线程 |
public final native void notifyAll() | 普通 | 唤醒所有等待的线程 |
- 栗子:
1 | package com.xxy.thread; |
11. 后台守护线程(daemon)
守护用户进程,例如GC进程,记录日志
方法 | 类型 | 说明 |
---|---|---|
public final void setDaemon(boolean var1) | 普通 | 设置为守护进程 |
public final boolean isDaemon() | 普通 | 判断是否为守护进程 |
- 栗子
1 | package com.xxy.thread; |
12. volatile关键字
volatile关键字不是描述同步的操作,而是可以更快捷的进行原始变量的访问,避免了副本创建和数据同步处理,事务的原子性用的比较多
13. 静态代理
- 栗子1:
- Marry接口
1 | package com.xxy.test; |
- You类
1 | package com.xxy.test; |
- 代理对象
1 | package com.xxy.test; |
- 主方法
1 | package com.xxy.test; |
14. Lambda表达式(jdk1.8新特性之一)
14.1 函数式接口
定义:任何一个接口只包含唯一的抽象方法,可以有多个非抽象方法,叫函数式接口,lambda就是匿名内部类
栗子1:
函数式接口
1 | package com.xxy.lambda; |
- 实现类
1 | package com.xxy.lambda; |
- lambda和主方法
1 | package com.xxy.lambda; |
15. 生产消费者问题
- 管程法:利用缓冲区
- 信号灯法:标志位解决
16. 线程池
避免频繁销毁和创建
1 | package com.xxy; |
17. 总结
总结多线程的基础,还没有线程池的内容。如果有错误和建议,欢迎评论指出。