JavaSE进阶——Day09 多线程(一)
该篇主要讲解Java中多线程的实现、线程安全问题和解决、线程的六种状态
线程简介
多任务
多线程
多条路同时进行
程序、进程、线程
操作系统运行的程序(静态概念)就是进程(动态概念)、一个进程拥有多个线程(互不影响)
很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。
核心概念
线程就是独立的执行路径
在程序运行时,即使没有自己创建线程,后台也会有多个线程,比如主线程,GC线程
main()称之为主线程,为系统的入口,用于执行整个程序
在一个进程中,如果开辟了多个线程,线程的运行是由调度器(cpu)安排调度的,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
对同一份资源操作时mm会存在资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销,如CPU调度时间,并发控制开销
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程实现(重点)
三种创建方式
Thread类
创建子类,继承
Thread
类;子类中重写
run()
方法;创建子类对象,调用
start()
开启线程。(其实对于单核CPU的线程之间是交替进行的)
测试案例:
1 | public class TestThread1 extends Thread { /* 需要继承Thread */ |
注意,线程开启不一定立即执行,是由CPU调度执行
Runnable接口
- 创建一个子类, 实现
Runnable
接口; - 在子类中,重写
Runnable
接口中的方法:run
(线程任务方法); - 创建
Thread
类对象, 并把实现了Runnable
接口的子类对象,作为参数传递给Thread
类对象
1 | new Thread(Runnable类型的对象) |
- 启动线程。
例:
1 | //创建一个子类, 实现`Runnable`接口并重写run方法 |
1 | //创建`Thread`类对象, 并把实现了`Runnable`接口的子类对象,作为参数传递给`Thread`类对象 |
多线程程序的开发方式:
方式1 :Thread
- 创建子类,继承Thread类 (不能在继承其他父类了)
- 子类中重写run方法 (线程任务)
- 创建子类对象,调用start方法(启动线程)
//线程任务、线程功能 全部都在Thread子类中
方式2 : Runnable
- 创建子类 ,实现Runnable (可以继承其他父类)
- 重写run方法 (线程任务)
- 创建Thread类对象, 并指定要执行的线程任务(Runnable实现类对象作为参数,传递到Thread类的构造方法中)
- Thread类对象.start() (启动线程)
//线程任务 : Runnable接口实现类
//线程功能 : Thread类
推荐使用Runnable接口的方式,好处:解耦
接口的作用:
- 制定规则
- 可以降低耦合 (耦合:紧密连接的程度) //程序都是要求低耦合
线程API的基本方法
控制线程
setPriority(int):设置线程的优先级别,可选范围1-10,默认为5,优先级高代表抢到时间片的概率高
static sleep(long):让当前的线程休眠指定毫秒数
static yield();让当前线程直接放弃时间片返回就绪【很可能自投自抢的情况,比较浪费CPU资源,建议少用】
join():让当前线程邀请调用方法的那个线程优先执行,在被邀请的线程执行结束之前当前线程一直处于阻塞状态,不再继续执行
其他常用方法:
setName():设置线程的名字
getName():得到线程的名字
static activeCount():得到程序中所有活跃的线程:就绪+运行+阻塞
setDaemon(true):设置线程成为守护线程(为了给别的线程提供服务的)
当程序当中只剩下守护线程的时候,守护线程会自行消亡(收尾工作 )
注意:
守护线程需要无限循环,防止其过早消亡
设置成为守护线程必须早于自己的start()
守护线程应该具有较低的优先级
interrupt():中断,打断线程中的阻塞状态
*:sleep()和join()都能导致线程阻塞
static currentThread():得到当前正在运行状态的线程对象
在主线程(main方法)当中,用于获得主线程对象,java当中唯一可以获得主线程对象的方式
在run()调用的其他方法中,用于获得当前线程
意事项:不应该出现在run方法体中,因为得到的线程就是this
………
原文链接:线程基本方法
线程安全问题
线程安全产生的原因
- 多个线程在对共享数据进行读改写的时候,可能导致的数据错乱就是线程的安全问题了
解决思想:线程的同步
概述 : java允许多线程并发执行,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证该变量的唯一性和准确性
分类
- 同步代码块
- 同步方法
- 锁机制。Lock
同步代码块
同步方法
同步方法:
修饰符号 synchronized 返回值类型 方法名(参数列表){
}
同步方法也有对象锁:
this锁 (当前对象锁)
类名.class (静态方法上的对象锁)
Lock锁
代码:
1 | package security.demo1; |
1 | package security.demo1; |