线程
多线程:
进程是系统分配资源的最小单位,线程是系统调度的最小单位,一个进程内的线程之间是可以共享资源的;线程是进程执行的最小单位,也是进程执行的实际单位;线程依附进程进行存活;进程好比工厂,线程好比流水线;进程不能共享资源,线程可以共享资源
每个进程至少有一个线程存在,即主线程;
线程可共享的资源:
1.打开的文件;
2.内存:对象
不可共享的资源:
线程自身的上下文,记账信息,状态不可共享
当线程的数量到达某个合适的值是最好的,如果有太多的线程,就会出现线程之间的争抢和CPU的过度调度问题,而CPU调度是需要消耗系统资源的,所以线程不是越多越好;
那多少线程是最好的?
要看具体的应用场景,密集计算的CPU任务、IO文件读写型任务
当使用场景是计算型任务时,线程的数量等于CPU的数量最好;
进程->线程(轻量化的进程)->协程(轻量化的线程)
查看当前线程的运行状况
首先创建一个线程:
在jdk自带的终端下进行观测
创建线程的方式:
1.继承Thread类是实现线程的创建线程-2种写法
继承重写Run
重写thread
2.实现Runnable接口的方式-3种
传入Runnable
创建时自带Runnable
直接重写run方法
callable接口实现
以上方法都不能拿到线程执行的返回值,
而callable接口可以
线程休眠:
面试题:
使用两个线程打印”AABBCCDD“,一个线程只能打印ABCD
创建Runnable任务,传递给两个线程即可;
线程的常见属性:
- ID: getId()
- 名称: getName()
- 状态: getState()
- 优先级: getPriority()
- 是否后台: isDaemon()
- 是否存活: isAlive()
- 是否被中断: isInterrupted()
ID属于每个线程的标识,不同线程不会重复
名称是各种调试工具
状态标识当前线程状态
优先级高的线程更容易被调度
JVM会再一个进程所有非后台线程结束后,才会结束运行
存活就是是否线程运行结束了
关于优先级:
优先级的取值是1-10;值越大线程的执行权重越高;
但JVM并不会严格按照优先级顺序执行线程
线程的类型:
- 后台类型-守护线程
- 用户线程-创建的默认
区别:守护线程用于服务用户线程,
进程退出:没有用户线程时,进程就会结束,无论守护线程是否结束
守护线程使用场景:JAVA的垃圾回收器;健康检查
守护线程注意事项:
1.必须在调用start()前设置;否则报错,且守护线程无效
2.在守护线程中创建的线程默认是守护线程;
线程的中断:
方式:1.通过共享的标记来进行沟通
2.调用interrupt()方法来通知
关于方式1:
方法1.
public class ThreadDemo {
private static class MyRunnable implements Runnable {
public volatile boolean isQuit = false;
@Override
public void run() {
while (!isQuit) {
System.out.println(Thread.currentThread().getName()
+ ": 别管我,我忙着转账呢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()
+ ": 啊!险些误了大事");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
System.out.println(Thread.currentThread().getName()
+ ": 让李四开始转账。");
thread.start();
Thread.sleep(10 * 1000);
System.out.println(Thread.currentThread().getName()
+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");
target.isQuit = true;
}
}
方法2.
直接调用interrupt()方法通知该线程停止运行
public class Thread2 {
private static class MyRunnable implements Runnable {
@Override
public void run() {
// 两种方法均可以
while (!Thread.interrupted()) {
//while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName()
+ ": 别管我,我忙着转账呢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()
+ ": 有内鬼,终止交易!");
break;
}
}
System.out.println(Thread.currentThread().getName()
+ ": 啊!险些误了大事");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
System.out.println(Thread.currentThread().getName()
+ ": 让李四开始转账。");
thread.start();
Thread.sleep(10 * 1000);
System.out.println(Thread.currentThread().getName()
+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");
thread.interrupt();
}
}
重点说明下第二种方法:
- 通过 thread 对象调用 interrupt() 方法通知该线程停止运行
- thread 收到通知的方式有两种:
a. 如果线程调用了 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式
通知,清除中断标志
b. 否则,只是内部的一个中断标志被设置,thread 可以通过
1. Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
2. Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
方式2;
能够更及时的收到通知,即使线程在Sleep也可以收到
第一种方法
public class ThreadDemo {
private static class MyRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("通过异常收到了中断情况");
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
thread.start();
thread.interrupt();
}
}
通过异常收到了中断情况,收到中断通知,且标志位被清楚
第二种方法
Thread.interrupted()//执行完状态判断之后,将状态复位为false,全局的线程终止后复位
Thread.currentThread().isInterrupted()//只查看当前线程的状态,不改变线程状态
方法 | 解释 |
---|---|
public void interrupt() | 中断对象关联的线程,如果线程阻塞,则以异常的方式通知,否则设置标志位 |
public static boolean interrupted() | 判断当前线程中断标志位是否设置,调用后清楚标志位 |
public boolean isInterrupted() | 判断对象关联的线程的标志位是否设置,调用后不清除标志位 |
线程的状态:
状态 | 解释 |
---|---|
NEW | 新建状态,没有调用start之前的状态 |
RUNNABLE | 运行状态,Running执行中,Ready就绪 |
BLOCKED | 阻塞状态, |
WAITING | 等待,无明确等待时间 |
TIME_WAITING | 超时等待,有明确的等待时间比如sleep |
TERMINATED | 终止状态 |