Java 线程系列Java 天生就是多线程

Posted 半身风雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 线程系列Java 天生就是多线程相关的知识,希望对你有一定的参考价值。


作者:半身风雪

上一篇:​​线程之间的共享和协作


@​​TOC​



前言

【Java


一、Java 中的线程

一个Java 程序从main() 方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但实际上Java

程序天生就是多线程程序,因为执行main() 方法的是一个名称为main 的线程。

public static void main(String[] args) 

// java 虚拟机线程系统的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor 和synchronizer 信息,仅仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
// 遍历线程,仅打印线程ID 和线程名称信息
for (ThreadInfo threadInfo : threadInfos)
System.out.println("线程ID" + threadInfo.getThreadId() + "线程名" + threadInfo.getThreadName());

上面代码输出的结果:

【Java

  1. $\\textcolorredMonitor Ctrl-Break$ 监控 Ctrl-Break 中断信号的
  2. $\\textcolorredSignal Dispatcher$ 分发处理发送给 JVM 信号的线程
  3. $\\textcolorred Finalizer $ 调用对象 finalize 方法的线程
  4. $\\textcolorredReference Handler$ 清除 Reference 的线程
  5. $\\textcolorred main $ main 线程,用户程序入口

从上面的例子中,我们能发现,在Java中短短的几行代码,就给我们启动了5个线程,当然,不同的版本,启动的线程数量也不一样,由此我们可以得出:**Java

天生就是多线程的**

1、启动

线程的启动方式有两种(源码中的注释是这么写的)参见代码:cn.enjoyedu.ch1.base.NewThread:

  1. X extends Thread;,然后 X.start
  2. X implements Runnable;然后交给 Thread 运行

示例代码:(派生自Thread 类,来实现我们的两种线程启动方式)

/**
* 扩展自Thread 类
*/
private static class UserThread extends Thread
@Override
public void run()
System.out.println("UserThread.run");



/**
* 扩展自 Runnable 类
*/
private static class UserRunnable implements Runnable

@Override
public void run()
System.out.println("UserRunnable.run");



public static void main(String[] args)

UserThread userThread = new UserThread();
userThread.start();

UserRunnable userRunnable = new UserRunnable();

new Thread(userRunnable).start();

Thread 和 Runnable 的区别:

  • ​Thread​​ 是Java 里对线程的唯一抽象。
  • ​Runnable​​ 是Java对任务(业务逻辑)的抽象。
  • ​Thread​​​ 可以接受任意一个​​Runnable​​ 的实例并执行。

2、中止

  • ​线程自然终止:​​要么是run 执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。
  • ​stop:​​暂停、恢复和停止操作对应在线程ThreadAPI就是​​suspend()、resume() 和 stop()​​。但是这些API都是过期的,不再建议使用。不建议使用的主要原因有:以​​suspend()​​​方法为例,在调用后,线程不会释放已占有的资源(比如锁),而是占有资源进入睡眠状态,这样容易引发死锁问题。同样,​​stop()​​​ 方法在终结一个线程时,不会保证线程的资源正常释放,通常是没有给予线程完成资源释放的机会,因此会到导致程序可能工作在不确定的状态下。整因为​​suspend()、resume() 和 stop()​​ 方法带来的副作用,这些方法才会被标注为不建议使用的过期方法中。
  • ​中断:​​​安全的中止则是其它线程通过调用线程A的​​interrupt()​​ 方法对其进行中止操作,中断代表着其它线程对A线程打了个招呼,“A, 你要中断了”,不代表线程A 会立即停止自己的工作,同样A线程可以不理会这种请求。因为Java 中的线程是协作式的,不是抢占式。线程通过检查自身的中断标志位是否被置为true来进行响应。
private static class UserThread extends Thread

public UserThread(String name)
super(name);


@Override
public void run()
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());

while (!isInterrupted())
// while (!Thread.interrupted())
// while (true)
System.out.println(threadName+ "is running");
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());

System.out.println(threadName+ "interrupt flag = " + isInterrupted());




public static void main(String[] args)
Thread endTread = new UserThread("endTread");
endTread.start();
try
Thread.sleep(20);
catch (InterruptedException e)
e.printStackTrace();

// 中断线程, 其实设置线程的标识位
endTread.interrupt();

运行上面的代码:

【Java

  • 我们发现,在使用​​isInterrupted()​​​ 进行线程中断的之后,​​isInterrupted()​​​会返回一个true。我们一起来看一下​​isInterrupted()​​ 方法的源码:

【Java

  • 我们再使用一下​​静态的 interrupted()​​ 方法,他返回的也是一个bool 值,先看一下这个方法的源码:

【Java

  • 从源码中我们发现,它返回也是中断标识符,但是,它把中断标识符给重新赋值成了true。我们来看一下运行效果

【Java

由此我们可以总结出:**线程通过方法 ​​isInterrupted()​​​来进行判断是否被中断,也可以调用静态方法 ​​Thread.interrupted()​​​来进行判断当前线程是否被中断,不过 ​​Thread.interrupted()​​​ 会同时将中断标识位改写为 ​​false​​。**


3、阻塞

  • 如果一个线程处于阻塞状态(​​如线程调用了 thread.sleep、thread.join、 thread.wait 等)​​​,则线程在检查中断标识时,如果发现中断标识位​​true​​​,则会在这些阻塞方法调用处抛出​​InterruptedException​​​ 异常,并且在抛出异常后会立即将线程的中断标识位清除,即重新设置为​​true​​。
private static class UserThread extends Thread

public UserThread(String name)
super(name);


@Override
public void run()
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());

while (!isInterrupted())
try
Thread.sleep(100);
catch (InterruptedException e)
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());
e.printStackTrace();


System.out.println(threadName+ "is running");


System.out.println(threadName+ "interrupt flag = " + isInterrupted());




public static void main(String[] args)
Thread endTread = new UserThread("endTread");
endTread.start();
try
Thread.sleep(Java 线程系列Java 天生就是多线程

Java 线程系列ThreadLocal进阶解析

Java 线程系列Java线程之间的共享和协作

Java 线程系列Java线程之间的共享和协作

Java 线程系列Java线程之间的共享和协作

Java 线程面试题总结2022