并发编程系列(一):线程基础

一、线程生命周期
通过start方法启动线程,当run()方法执行完毕,线程生命周期即将终止

线程6种状态

  1. NEW:初始状态,线程被创建,还没调start方法
  2. RUNNING:运行状态,就绪ready和运行两种统一称为“运行中”
  3. WAITING:等待状态
  4. TIME_WAITING:超时等待状态,超市以后自动返回
  5. TERMINATED:终止状态,表示线程执行完毕
  6. BLOCKED:阻塞状态表示线程进入等待状态,也就是线程因为某些原因放弃了CPU的使用权,有如下几种情况
  • 等待阻塞:运行线程调用了wait方法,jvm会把当前线程放入等待队列列
  • 同步阻塞:当前线程获取对象同步锁时,锁已被其他线程占用,jvm会把当前线程放入锁池
  • 其他阻塞:运行线程执行Thread.sleep或者t.join()方法,或是发出I/O请求,jvm会把当前线程设置为阻塞状态,当sleep结束、join线程终止、io处理完毕则线程恢复
    在这里插入图片描述
    线程状态查看
  1. 通过jps命令查看当前环境下运行的所有java进程pid
  2. 通过stack pid命令查询当前线程的状态。jstack是java虚拟机自带的一个堆栈跟踪工具,用于打印java进程ID,core file或远程调试服务的java堆栈信息。

二、线程启动原理

  • 问题:为什么用start方法,而不直接执行run方法? 在JVM层面创建线程,并在线程的start里面调用了run方法

进入start方法源码,内部调用了native方法start0(),start0是在Thread静态块中注册的
在这里插入图片描述
registerNative方法定义在Thread.c文件中,其定义了各操作系统平台要用的关于线程的公共数据和操作。
参照地址Thread.c文件内容
在这里插入图片描述
在java虚拟机中,首先创建一个和平台相关的java线程,通过操作系统启动start方法,在该方法中最终会调用到run方法

jvm源码查看Hotspot源码

三、线程终止

  • 问题:如何终止一个线程?

stop(),过时方法。使用该方法结束线程不会保证线程资源正常释放,可能出现一些不确定的状态

1、线程中断方法interrupt()
通过在线程外部调用interrupt方法,向线程发出中断信号,告诉线程可以中断了,但何时中断取决于线程自己。
线程通过自身的isInterrupted()判断,是否被中断。
eg.

public class InterruptDemo {
    private static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            // 默认情况isInterrupted返回false,通过thread.interrupt()变成true
            while (!Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("Num: " + i);
        }, "interruptDemo");

        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt(); // 加和不加的效果
    }
}

通过标识位或中断操作,使线程终止前,有机会去清理资源,而不是武断的将线程停止,这种方式更优雅。

2、线程静态方法Thread.interrupted()
外面线程thread.interrupt(),设置中断标识,告诉线程可以终止了。
线程内部通过Thread.interrupted(),将线程标识状态复位。
eg.

public class InterruptDemo2 {
    private static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (true) {
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("before: " +
                            Thread.currentThread().isInterrupted());
                    Thread.interrupted(); //对线程复位,由true>false
                    System.out.println("after: " +
                            Thread.currentThread().isInterrupted());

                }
            }

        }, "interruptDemo");

        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
    }
}

3.其他情况复位(被动复位)
对于抛出InterruptedException异常的方法,JVM辉县把中断标识清除,然后才抛出InterruptedException异常,这个时候如果调用isInterrupted方法,会返回false
eg1.正常中断,状态为true

public class InterruptDemo3 {
    private static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (!Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("Num: " + i);
        }, "interruptDemo");

        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
        System.out.println("interrupt state: " + thread.isInterrupted());
    }
}

eg2.中断抛异常,状态为false

public class InterruptDemo4 {
    private static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
            System.out.println("Num: " + i);
        }, "interruptDemo");

        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt(); 
        System.out.println("interrupt state: " + thread.isInterrupted());
    }
}

4.复位原因
复位:自身没有真正中断,所以线程内部会复位,什么时候中断取决于自身

两个作用:
(1)返回当前中断标识true
(2)对中断标识复位,表明响应过中断请求

5.中断原理
(1)interrupt方法内部原理
java源码会调用native方法interrupt0,在java虚拟机中会调用平台的interrupt方法,在文件os_*.cpp中,不同平台会使用不同的文件,因为java是跨平台的,最后通过set_interrupted()方法设置中断标识为true

(2)isInterrupted()
若中断标识为true,则先清除中断标识,也即通过set_interrupted()方法将中断标识还原,并抛出异常InterruptedException

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值