【多线程】多线程(一)
1. 线程(Thread)
1.1 概念
进程是系统分配资源的最小单位,线程是系统调度的最小单位。一个进程内的线程之间是可以共享资源的。
每个进程至少有一个线程存在,即主线程。
1.2 创建线程的方法
1.3 多线程的优势-增加运行速度
提高CPU的利用率,更好地利用系统资源,使用Monitor类可以同步静态/实例化的方法的全部代码或者部分代码段,使用不同的同步类创建自己的同步机制。
多线程的好处提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,大大提高程序的效率。
采用多线程技术的应用程序可以更好地利用系统资源。主要优势在于充分利用了CPU的空闲时间片,用尽可能少的时间来对用户的要求做出响应,使得进程的整体运行效率得到较大提高,同时增强了应用程序的灵活性。由于同一进程的所有线程是共享同一内存,所以不需要特殊的数据传送机制,不需要建立共享存储区或共享文件,从而使得不同任务之间的协调操作与运行、数据的交互、资源的分配等问题更加易于解决。
线程同步,在多线程应用中,考虑不同线程之间的数据同步和防止死锁。当两个或多个线程之间同时等待对方释放资源的时候就会形成线程之间的死锁。为了防止死锁的发生,需要通过同步来实现线程安全。在Visual Basic中提供了三种方法来完成线程的同步。在Java中可用synchronized关键字。
2. Thread 类及常见方法
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
2.1 Thread 的常见构造方法
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");
2.2 Thread 的几个常见属性
-
ID 是线程的唯一标识,不同线程不会重复
-
名称是各种调试工具用到
-
状态表示线程当前所处的一个情况,下面我们会进一步说明
-
优先级高的线程理论上来说更容易被调度到
-
关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
-
是否存活,即简单的理解,为 run 方法是否运行结束了
package thread_0425;
/**
* Created by JiaLe on 2021/4/25 21:09
*/
public class ThreadDemo11 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
},"张三");
System.out.println(t1.getState());
t1.start();
System.out.println(t1.getState());
System.out.println(t1.getId());
//新创建的优先级默认为5
//最小的优先级为1
//最大的优先级为10
//优先级的值越大,优先级越高,可能被优先执行的概率越高
System.out.println(t1.getPriority());
System.out.println(t1.getName());
System.out.println(t1.isAlive());
/**
* 线程分类
* 用户线程
* main方法为用户线程
* 守护线程
* 守护线程是用来服务用户线程的
* 当进程中没有用户线程运行,进程就会结束
* 守护线程使用场景:Java垃圾回收器
* TCP健康检测
* 守护线程注意事项:
* 守护线程属性的设置必须放在线程启动(start)之前,如果在之后,程序会报错(状态未找到),而且设置的属性不会生效
* 在守护线程里创建的线程默认情况下都是守护线程
*/
System.out.println(t1.isDaemon());
System.out.println(t1.isInterrupted());
}
}
输出结果:
2.3 启动一个线程-start()
通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。
覆写 run 方法是提供给线程要做的事情的指令清单,线程对象可以认为是把 李四、王五叫过来了 ;
而调用 start() 方法,就是喊一声:”行动起来!“,线程才真正独立去执行了。
2.4 中断一个线程
李四一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。
目前常见的有以下两种方式:
1. 通过共享的标记来进行沟通
2. 调用 interrupt() 方法来通知
重点说明下第二种方法:
1. 通过 thread 对象调用 interrupt() 方法通知该线程停止运行
2. thread 收到通知的方式有两种:
1. 如果线程调用了 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志
2. 否则,只是内部的一个中断标志被设置,thread 可以通过
1. Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
2. Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
2.4 线程休眠
线程休眠的三种方式:
package thread_0425;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Created by JiaLe on 2021/4/25 20:25
*/
public class ThreadDemo8 {
public static void main(String[] args) throws InterruptedException {
System.out.println("开始时间:" + new Date());
//休眠方式1 休眠1s
Thread.sleep(1000);
//休眠方式2
TimeUnit.SECONDS.sleep(1);
//休眠方式3
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
System.out.println("结束时间:" + new Date());
}
}
实现方法一:
优点:精确度很高。
缺点:当休眠时间过大时,代码书写较复杂。
实现方法二三:
当休眠较长时间,可用实现方法二和实现方法三。