0
点赞
收藏
分享

微信扫一扫

java并发原理实战(3) -- 线程的中断和初始化


线程的中断和初始化

  • ​​1.多线程中start和run方法的区别?​​
  • ​​2.Thread.currentThread()与this的区别​​
  • ​​3.后台进程setDaemon有啥用​​
  • ​​4.线程的中断​​
  • ​​①暴力停止stop(不建议使用)​​
  • ​​为啥不推荐:​​
  • ​​②通过中断标志中断(推荐)​​
  • ​​③中断线程推荐写法:使用三个反人类的方法+抛出异常方方式​​
  • ​​5.暂停线程(不推荐使用)​​
  • ​​①独占资源:​​
  • ​​②不同步​​
  • ​​6.线程初始化​​

1.多线程中start和run方法的区别?

参考链接:

start源码:

java并发原理实战(3) -- 线程的中断和初始化_多线程

1。start():

先来看看Java API中对于该方法的介绍:

​ 使该线程开始执行;Java 虚拟机调用该线程的 ​​run​​ 方法。

​ 结果是两个线程并发地运行;当前线程(从调用返回给 ​​start​​​ 方法)和另一个线程(执行其 ​​run​​ 方法)。

多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。

用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体中的代码执行完毕而直接继续执行后续的代码。通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里的run()方法 称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

2。run():

同样先看看Java API中对该方法的介绍:

​ 如果该线程是使用独立的 ​​Runnable​​​ 运行对象构造的,则调用该 ​​Runnable​​​ 对象的 ​​run​​ 方法;否则,该方法不执行任何操作并返回。

​ Thread​​ 的子类应该重写该方法。

run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

3。总结:

调用start方法方可启动线程,而run方法只是thread类中的一个普通方法调用,还是在主线程里执行。

2.Thread.currentThread()与this的区别

参考链接:

在自定义线程类时,如果线程类是继承java.lang.Thread的话,那么线程类就可以使用this关键字去调用继承自父类Thread的方法,this就是当前的对象。

另一方面,Thread.currentThread()可以获取当前线程的引用,一般都是在没有线程对象又需要获得线程信息时通过Thread.currentThread()获取当前代码段所在线程的引用。

3.后台进程setDaemon有啥用

​设置守护线程 其他线程执行完,即使他自己没有执行完,他也会退出​

演示1:

java并发原理实战(3) -- 线程的中断和初始化_初始化_02


java并发原理实战(3) -- 线程的中断和初始化_java_03

运行结果:

java并发原理实战(3) -- 线程的中断和初始化_java_04

把demo2的代码放开:

java并发原理实战(3) -- 线程的中断和初始化_多线程_05

看下结果:

java并发原理实战(3) -- 线程的中断和初始化_初始化_06

结果显示: 一直在执行,说明一个问题。demo1守护着demo2在运行,如果没有别的线程在运行他也得死掉。这保镖很敬业!!

4.线程的中断

①暴力停止stop(不建议使用)

java并发原理实战(3) -- 线程的中断和初始化_java_07

2秒后,线程停止:

java并发原理实战(3) -- 线程的中断和初始化_初始化_08

为啥不推荐:

原因:

①:直接给退出线程了,那我一直用的资源得不到释放
​ ②:释放锁,造成数据不一致。

  • 原因1示例:
  • java并发原理实战(3) -- 线程的中断和初始化_初始化_09


  • java并发原理实战(3) -- 线程的中断和初始化_并发编程_10

  • 原因二实例:
  • java并发原理实战(3) -- 线程的中断和初始化_多线程_11


  • java并发原理实战(3) -- 线程的中断和初始化_并发编程_12


  • java并发原理实战(3) -- 线程的中断和初始化_初始化_13

②通过中断标志中断(推荐)

这里java设计的api,三个反人类的方法:

java并发原理实战(3) -- 线程的中断和初始化_初始化_14

傻傻分不清楚:

  • interrupt(): 实例对象方法
  • java并发原理实战(3) -- 线程的中断和初始化_并发编程_15

  • interrupted 静态方法: 这相当于一个 测试方法,测试一下,当前的线程是 中断的线程吗?测试完事后,将当前行线程的中断标志改为false。
  • java并发原理实战(3) -- 线程的中断和初始化_初始化_16


  • java并发原理实战(3) -- 线程的中断和初始化_初始化_17

  • isInterrupted

isTnterrupted:普通方法,也是一个测试方法,看下调用的对象是中断了吗?和上面不同的是,他不清除中断标志。原来中断标志是啥还是啥。

java并发原理实战(3) -- 线程的中断和初始化_java_18

③中断线程推荐写法:使用三个反人类的方法+抛出异常方方式

代码演示:

java并发原理实战(3) -- 线程的中断和初始化_多线程_19


运行结果:

java并发原理实战(3) -- 线程的中断和初始化_并发编程_20

说明: 线程1被清除了。

这算是中断线程最好的方式,更多可以看下《java多线程核心技术》这本书,里面还有沉睡的线程停止,异常方法停止也就是现在说的,还有3个反人类方法+return方式,但是最好的这里说了。

5.暂停线程(不推荐使用)

过时的方法,不说也可以,但是看到以前的代码还是需要了解下的:

java并发原理实战(3) -- 线程的中断和初始化_多线程_21

不推荐使用的原因:

①独占资源:

java并发原理实战(3) -- 线程的中断和初始化_并发编程_22

  • 独占资源的情况1:
  • java并发原理实战(3) -- 线程的中断和初始化_初始化_23


  • java并发原理实战(3) -- 线程的中断和初始化_java_24

运行结果:

java并发原理实战(3) -- 线程的中断和初始化_多线程_25

  • 独占资源的情况2(使用print的时候):
  • java并发原理实战(3) -- 线程的中断和初始化_java_26

结果显示:没问题,线程被暂停了,没机会执行了,main方法退出了也就。接下来,变下

java并发原理实战(3) -- 线程的中断和初始化_并发编程_27


java并发原理实战(3) -- 线程的中断和初始化_多线程_28

②不同步

java并发原理实战(3) -- 线程的中断和初始化_多线程_29


java并发原理实战(3) -- 线程的中断和初始化_java_30


java并发原理实战(3) -- 线程的中断和初始化_多线程_31

6.线程初始化

看下线程的几个构造方法

java并发原理实战(3) -- 线程的中断和初始化_多线程_32

点看会看到

java并发原理实战(3) -- 线程的中断和初始化_多线程_33


java并发原理实战(3) -- 线程的中断和初始化_初始化_34


java并发原理实战(3) -- 线程的中断和初始化_多线程_35

private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}

this.name = name;

Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */

/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}

/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}

/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();

/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}

g.addUnstarted();

this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;

/* Set thread ID */
tid = nextThreadID();
}

全部调用的都是init方法,干了啥呢?

1)创建你的线程,就是你的父线程
2)默认的ThreadGroup就是父线程的ThreadGroup
3)默认的daemon状态是父线程的daemon状态
4)默认的优先级是父线程的优先级
5)默认的线程名称是Thread-X的形式
6)线程id是从1开始的全局递增。


举报

相关推荐

0 条评论