标签:run方法 不同 stack waiting demo 完成 ted system 触发事件
场景-->需求-->解决方案-->应用-->原理
真空管和穿孔打卡
操作员在机房里面来回调度资源,以及计算机同一个时刻只能运行一个程序,在程序输入的过程中,计算机计算机和处理空闲状态 。而当时的计算机是非常昂贵的,人们为了减少这种资源的浪费。就采用了 批处理系统来解决
晶体管和批处理系统
批处理操作系统虽然能够解决计算机的空闲问题,但是当某一个作业因为等待磁盘或者其他 I/O 操作而暂停时,那CPU 就只能阻塞直到该 I/O 完成,对于 CPU 操作密集型的程序,I/O 操作相对较少,因此浪费的时间也很少。但是对于 I/O 操作较多的场景来说,CPU 的资源是属于严重浪费的
集成电路和多道程序设计
有了进程以后,可以让操作系统从宏观层面实现多应用并发。而并发的实现是通过 CPU 时间片不端切换执行的。对于单核 CPU 来说,在任意一个时刻只会有一个进程在被CPU 调度
在多核 CPU 中,利用多线程可以实现真正意义上的并行执行
在一个应用进程中,会存在多个同时执行的任务,如果其中一个任务被阻塞,将会引起不依赖该任务的任务也
被阻塞。通过对不同任务创建不同的线程去处理,可以提升程序处理的实时性
线程一共有 6 种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIME_WAITING、TERMINATED)以枚举的方式存储在Thread类内部
代码示例
public class ThreadStatusDemo {
public static void main(String[] args) {
//新建线程执行sleep方法
new Thread(()->{
while(true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Time_Waiting_Thread").start();
//新建线程执行await方法,需要notify唤醒,进入阻塞状态
new Thread(()->{
while(true){
synchronized (ThreadStatusDemo.class) {
try {
ThreadStatusDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Wating_Thread").start();
//添加通过锁,进行锁争抢 为争抢到锁的线程进入BLOCKED
new Thread(new BlockedDemo(),"Blocke01_Thread").start();
new Thread(new BlockedDemo(),"Blocke02_Thread").start();
}
static class BlockedDemo extends Thread{
@Override
public void run() {
synchronized (BlockedDemo.class){
while(true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
启动一个线程前,最好为这个线程设置线程名称,因为这样在使用 jstack 分析程序或者进行问题排查时,就会给开发人员提供一些提示;
线程的启动(start()方法和run方法的联系和区别),进入start底层,会发现调用了native方法,也就是外部方法,jvm中实现的方法start0,它在底层实现了对run方法的调用;主线程可以调用run方法,不过那是调用实体类的方法,属于主线程,不属于多线程,多次调用同一线程的start方法,会出现场错误;
线程的停止
interrupt() 方法
通过interrupt() 方法,发出中断标志,程序根据标志判断是是否停止线程,interrupt()并不能停止线程,它和return,特定循环中的break可以停止到当前的线程
public class StopThread extends Thread {
@Override
public void run() {
while (true){
if(Thread.currentThread().isInterrupted()){
System.out.println("线程被中断了");
break;
}
}
System.out.println("这是收到中断标志,跳出循环");
}
}
//main方法
public class Run {
public static void main(String[] args) throws InterruptedException {
Thread s = new StopThread();
s.start();
Thread.sleep(10);
s.interrupt();
}
}
虽然中断标志收到跳出了循环,但是线程后面的程序仍然继续执行了
抛异常
public class StopThreadUseException extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i <500000 ; i++) {
if(this.isInterrupted()){
System.out.println("线程被中断了");
throw new InterruptedException();
}
System.out.println("i:"+i);
}
System.out.println("for后面的代码");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//main方法
public class Run {
public static void main(String[] args) throws InterruptedException {
// Thread s = new StopThread();
Thread s = new StopThreadUseException();
s.start();
Thread.sleep(10);
s.interrupt();
}
}
运行结果:执行的线程收到信号,抛出异常,并且跳出for的代码没有继续执行
stop方法:不安全,资源为完全退出,多线程中会导致数据不一致(已执行代码所修改的类变量不会还原)
中断复位
Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号,但不会立刻中断自己,具体什么时候中断由自己决定,让外界知道在自身中断前,他的中断状态仍然是 false,这就是复位的原因。,thread.interrupt()方法实际就是设置一个 interrupted 状态标识为 true、并且通过ParkEvent 的 unpark 方法来唤醒线程。
对于 synchronized 阻塞的线程,被唤醒以后会继续尝试获取锁,如果失败仍然可能被 park
在调用 ParkEvent 的 park 方法之前,会先判断线程的中断状态,如果为 true,会清除当前线程的中断标识
Object.wait 、 Thread.sleep 、 Thread.join 会 抛 出InterruptedException?
你会发现这几个方法有一个共同点,都是属于阻塞的方法,阻塞方法的释放会取决于一些外部的事件,但是阻塞方法可能因为等不到外部的触发事件而导致无法终止,所以它允许一个线程请求自己来停止它正在做的事情。当一个方法抛出 InterruptedException 时,它是在告诉调用者如果执行该方法的线程被中断,它会尝试停止正在做的事情并且通过抛出 InterruptedException 表示提前返回。所以,这个异常的意思是表示一个阻塞被其他线程中断了。然 后 , 由 于 线 程 调 用 了 interrupt() 中 断 方 法 , 那 么
Object.wait、Thread.sleep 等被阻塞的线程被唤醒以后会通过 is_interrupted 方法判断中断标识的状态变化,如果发现中断标识为 true,则先清除中断标识,然后抛出InterruptedException
标签:run方法 不同 stack waiting demo 完成 ted system 触发事件
原文地址:https://www.cnblogs.com/liweiweicode/p/12382737.html