多线程
1.多线程概要
Thread : 多任务执行,多路径执行
线程是程序中的执行顺序流。 Java 虚拟机允许应用程序同时运行多个执行线程。
三高网站 : 高可用 高性能 高并发
线程与进程之间的区别 : 看文档
多线程的优点 : 资源利用率更好,性能更高,效率更高
多线程的缺点 : 设计复杂,可能造成数据不安全
线程的创建方式 :
1.继承Thread,重写run方法 + start开启线程
2.实现Runnable接口,重写run方法 + start开启线程
优点 :
1.类单继承,接口可以多实现
2.实现资源共享
3.实现juc包下Callable接口,重写call方法 + 线程池
优点 :
1.可以抛出异常
2.可以带出返回值
2.实现步骤
1.继承Thread
重写run方法 + start开启线程
public class Class001_Thread extends Thread{
/*
定义线程体
*/
@Override
public void run() {
for(int i = 0;i<=100;i++){
System.out.println("一边喝水.....");
}
}
public static void main(String[] args) {
//主线程
// 创建线程对象
Class001_Thread th = new Class001_Thread();
//开启线程(准备好了)
th.start();
for(int i = 0;i<=100;i++){
System.out.println("一边讲课.....");
}
}
}
2.实现Runnable接口
重写run方法 + start开启线程
public class Class002_Thread implements Runnable{
/*
定义线程体
*/
@Override
public void run() {
for(int i = 0;i<=100;i++){
System.out.println("一边喝水.....");
}
}
public static void main(String[] args) {
//主线程
//线程所在类型对象
Class002_Thread cs = new Class002_Thread();
// 创建线程对象
Thread th = new Thread(cs);
//开启线程(准备好了)
th.start();
for(int i = 0;i<=100;i++){
System.out.println("一边讲课.....");
}
}
}
3.内部类定义线程体
//静态内部类
static class Inner1 implements Runnable{
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.println("一边打游戏");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
//局部内部类
class Inner2 implements Runnable{
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.println("一边陪女朋友");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
new Thread(new Inner1()).start();
new Thread(new Inner2()).start();
//匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
for(int i=1;i<=20;i++){
System.out.println("一边骂人..");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
//lambda表达式
new Thread(()->{
for(int i=1;i<=20;i++){
System.out.println("一边吸烟..");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
3.线程状的五种态
1.新生状态 : new
2.就绪状态 : start
进入就绪状态的线程会进入到就绪队列,等待cpu的调度
如何让线程进入到就绪状态 :
1.start
2.yield礼让线程
yield : 礼让线程
在多线程编程中,当一个线程调用yield函数时,它暂时放弃了对CPU的控制权,让其他线程有机会运行。具体来说,yield会把当前线程状态设置为可运行状态,并将CPU资源分配给其他线程。
当其他线程运行完或者被系统中断后,原先调用yield函数的线程可以再次获得CPU的控制权,并继续执行。这是因为yield只是暂时放弃了控制权,并没有完全释放线程资源。
需要注意的是,yield并不能保证线程调度的顺序,具体哪个线程会获得CPU资源是由操作系统的调度器决定的。所以,尽管一个线程可能调用了yield,但并不能保证它会立即获得CPU的控制权。
当一个线程调用yield,会从运行恢复到就绪状态,同时让出cpu的资源
static void yield() 向调度程序提示当前线程愿意放弃其当前对处理器的使用。
3.cpu的调度切换
4.阻塞解除
3.运行状态 :cpu调度执行
4.阻塞状态 : 无法正常运行
如何让线程进入到阻塞状态 :
1.sleep
sleep : 线程休眠
static void sleep(long millis) 使当前执行的线程休眠(暂时停止执行)指定的毫秒数,取决于系统计时器和调度程序的精度和准确性。
线程会进入阻塞状态,同时让出cpu的资源
抱着资源睡觉,抱着对象的锁资源睡觉
作用 :
1.模拟网络延迟
2.放大问题出现的可能性
2.join
join : 插队线程 | 合并线程
final void join() 等待这个线程死掉。
final void join(long millis) 最多等待millis毫秒让该线程终止。
final void join(long millis, int nanos) 最多等待millis毫秒加上nanos纳秒,以使该线程终止。
注意 : 先就绪后插队
3.wait
4.IO
5.终止状态
如何让线程进入终止状态 :
1.正常执行到终止
2.stop…不推荐
3.通过添加标识判断方式–>推荐
注意 :
一旦一个线程进入到终止状态无法恢复
一个线程当阻塞状态解除会直接恢复到就绪状态
6.getState
getState :获取 当前线程的 状态
线程状态。 线程可以处于以下状态之一:
NEW -> 新生 尚未启动的线程处于此状态。
RUNNABLE --> 就绪 |运行 在 Java 虚拟机中执行的线程处于这种状态。
BLOCKED ->阻塞等待获取对象锁 阻塞等待监视器锁的线程处于此状态。
WAITING ->等待其他线程执行特点操作 join() wait()… 无限期等待另一个线程执行特定操作的线程处于此状态。
TIMED_WAITING ->与时间相关的阻塞 sleep(ms) join(ms) wait(ms) ... 等待另一个线程执行操作达指定等待时间的线程处于此状态。
TERMINATED ->终止状态 已退出的线程处于此状态。
4.守护线程 :
当所有的用户线程全部执行完毕,守护线程无论是否执行完毕,JVM都会直接退出
守护线程是用来守护用户线程的
当创建一个线程默认为用户线程,如果想要 设置成为守护线程 final void setDaemon(boolean on) 将此线程标记为daemon线程或用户线程。 true->守护 false->用户
注意 : 垃圾回收机制是典型守护线程
先设置守护后设置就绪
5.中断线程 :
void interrupt() 中断这个线程。为当前调用interrupt方法的线程设置中断标识
static boolean interrupted() 测试当前线程是否被中断。 判断当前正在执行的线程是否曾经调用interrupt方法添加过中断标识,同时复位标识
boolean isInterrupted() 测试此线程是否已被中断。判断调用isInterrupted方法的线程是否曾经调用interrupt方法添加过中断标识
注意 : InterruptedException - 如果有任何线程中断了当前线程。 抛出此异常时清除当前线程的中断状态。
6.线程优先级 :
当大一个线程优先执行可能性
1~10 1最小 10最大 5默认
final int getPriority() 返回此线程的优先级。
final void setPriority(int newPriority) 更改此线程的优先级。
static final int MAX_PRIORITY 线程可以拥有的最大优先级。
static final int MIN_PRIORITY 线程可以拥有的最低优先级。
static final int NORM_PRIORITY 分配给线程的默认优先级。
注意 :如果在 一个线程已经结束之后修改优先级,这个修改没有效果
*7.线程安全 :
多个线程同时操作同一份资源,才有可能遇到线程数据不安全问题–>需要控制安全
同步锁 :
原理 : 让多个线程执行某段有可能影响数据安全的一段代码的时候,排队执行
实现关注两个部分 :
1.控制|协调多个线程排队执行的条件
锁定一个对象,利用对象锁机制控制
this : 索引使用的是当前调用成员方法的对象
类的Class对象 : 每一个类只有一个,不会改变,在类加载到内存之后已经存在
获取一个类的Class对象 : 类名.class
资源(对象)
2.多个线程排队执行的代码范围
使用语法 :
同步方法 : 使用synchronized关键字修饰方法
排队执行的代码范围 : 整个方法体
协调多个线程排队执行的条件 :
成员方法 : this
静态方法 : 类的Class对象
同步块 :多个线程排队执行同步块{}中的代码
synchronized(条件){
排队执行代码段;
}
当锁类的时候,相当于锁了这个类的所有对象,无论创建了这个类的多少个对象,这个类的Class对象只有一个,如果只想要锁这个类的某一个对象,建议使用this|具体对象
当锁this的时候,相当于锁了这个对象的所有资源(成员),当指向锁具体 的某一个资源的时候,可以锁资源
注意 :
锁不变的东西,自定义引用数据类型的对象地址一定不变