如何构造线程

在运行线程之前需要先构造线程对象,线程对象的构造需要指定线程所需要的属性,比如:所属线程组、线程优先级、是否为Daemon线程等信息。下面我们看一下,java.lang.Thread中对线程初始化的方法:

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(); /*
* 是否有访问权限
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
} g.addUnstarted();
//线程组
this.group = g;
//使用父线程的daemon、priority属性
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; /* 分配一个线程ID */
tid = nextThreadID();
}

一个 新 构造 的 线程 对象 是 由其 parent 线程 来 进行 空间 分配 的, 而 child 线程 继承 了 parent 是否 为 Daemon、 优先级 和 加载 资源 的 contextClassLoader 以及 可继承 的 ThreadLocal, 同时 还会 分配 一个 唯一 的 ID 来 标识 这个 child 线程。 至此, 一个 能够 运行 的 线程 对象 就 初始化 好了, 在 堆 内存 中 等待 着 运行。

我们构造一个Thread thread=new Thread(),打上断点,可以看到thread对象的属性如下:

如何使用线程

实现多线程编程的方式主要有两种:一种是继承Thread类,一种是实现Runnable接口,使用继承Thread类最大的局限性是不支持多继承,由于java单继承的特性,为了突破单继承的限制,于是就有了另一个实现方式,就是实现Runnable接口。使用这两种方式创建的线程工作性质是一样的,没有本质的区别。

继承Thread类

public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("我是自定义线程MyThread");
}
}

实现Runnable接口

public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("我是Runnable");
}
}

如何启动线程

线程对象初始化完成后,调用线程的start()方法就可以启动线程了,start()方法是告诉Java虚拟机,如果线程规划期空闲,应该立即启动调用了start()方法的线程。

同一个线程不能多次 调用 start() 方法, 否则会出现异常 Exception in thread” main” java. lang. IllegalThreadStateException。

线程的start()方法,会新启动一个线程,而线程run()方法则是同步等待当前线程调用。

如何停止线程

如何判断线程是否停止

在介绍如何停止线程的知识点前, 先看一下如何判断线程是否停止的状态。 Thread.java类中提供了两个很重要的方法:

1) this.interrupted(): 判断当前线程是否已经中断

2) this.isInterrupted(): 判断线程是否已经中断

那么这两种方法的区别是什么呢? 先来看看 this.interrupted()方法: 判断当前线程是否已经中断,当前线程是指运行 this. interrupted()方法 的 线程。

 public static void main(String[] args) {
Thread.currentThread().interrupt();
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted());
System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted()); }
main 当前线程是否已停止:=true
main 当前线程是否已停止:=false

从执行结果可知 interrupt()方法确实停止了线程,但是第二个判断结果为什么是false呢,通过查看官方文档当解释得知。interrupted() 具有清除状态的功能,所以第二个判断结果为false

下面我们接着查看 isInterrupted()方法:

public static void main(String[] args) {
Thread.currentThread().interrupt();
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted());
System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted()); } main 当前线程是否已停止:=true
main 当前线程是否已停止:=true

输出的结果都为true,isInterrupted()并未清除状态标志,最后我们得出如下结论:

1) this.interrupted(): 判断线程终止的状态, 执行后具有将状态标志置为false的功能

2) this.isInterrupted():判断线程终止的状态,不具有清除状态标志的功能

try..catch与this.interrupt方法终止线程

public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 5000; i++) {
if (interrupted()) {
System.out.println(Thread.currentThread().getName() + " 我被停止了,退出循环");
break;
}
System.out.println(" i=" + (i + 1));
}
}
} public static void main(String[] args) {
MyThread thread = new MyThread();
thread.setName("Thread-interrupt-0");
thread.start();
try {
Thread.sleep(1);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 结束!");
} 输出结果:
.....
i=32
i=33
i=34
i=35
i=36
i=37
i=38
i=39
i=40
i=41
结束!
Thread-interrupt-0 我被停止了,退出循环

过期的 suspend()、 resume() 和 stop()方法终止线程

suspend()在调用后线程不会释放已经占有的资源,二是占有着资源进入睡眠状态,这样容易引发死锁问题。同样的stop()方法在终止一个线程时不会保证线程的资源正常释放,通常线程没有机会去释放资源,因此会导致程序工作状态的不确定性。

正是因为 suspend()、 resume() 和 stop() 方法 带来的副作用, 这些方法才被标志位不建议使用的过期方法, 而暂停和恢复可以使用 等待/ 通知机制 来替代。

Java线程的启动和停止(一)的更多相关文章

  1. Java线程的启动与中止

    一.线程与进程的关系 关于进程与线程,百度百科上是这样描述的: 进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 在当 ...

  2. 面试官:Java 线程如何启动的?

    摘要:Java 的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢? 本文分享自华为云社区<Threa ...

  3. Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程

    下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...

  4. java -jar shell 启动、停止

    启用 vi start.sh #!/bin/sh # ################################################################## # Powe ...

  5. java线层的启动与停止

    class Do8 { public static void main(String[] args) { Resource r =new Resource(); Input in =new Input ...

  6. JAVA线程初体验

    线程的创建 线程的启动和停止 /** * 演员类 继承Thread类 * @author Administrator * */ public class Actor extends Thread { ...

  7. Java线程池的那些事

    熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但 ...

  8. 基于 JVMTI 实现 Java 线程的监控(转)

    随着多核 CPU 的日益普及,越来越多的 Java 应用程序使用多线程并行计算来充分发挥整个系统的性能.多线程的使用也给应用程序开发人员带来了巨大的挑战,不正确地使用多线程可能造成线程死锁或资源竞争, ...

  9. 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考

    2018年12月12日18:44:53 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考 案件现场 不久前,在开发改造公司一个端到端监控日志系统的时候,出现了一 ...

随机推荐

  1. winfrom 保存图片

    private void btnSave_Click(object sender, EventArgs e) { SaveFileDialog sfd = new SaveFileDialog(); ...

  2. setTimeout与setInterval的使用

    setTimeout:间隔一段时间后执行,只执行一次. function show(){ console.log(1); } setTimeout(show(),200);//直接执行无延时 setT ...

  3. JS原生实现照片抽奖

    HTML表格标记实现九宫格,放入九张图片.利用CSS的滤镜属性控制图片的透明度.Javascript实现抽奖和中奖. 可以做为教师上课,随机抽取回答问题的同学,使学生感受到随机的公平性,简单有趣! 点 ...

  4. Dubbo 配置参数

    关闭启动检查 在dubbo多模块项目启动的时候为了并行启动多个服务,缩短启动时间,需要解除模块之间的依赖检测 dubbo.consumer.check=false @Reference(check = ...

  5. SQL优化的总结和一些避免全盘扫描的注意事项

    1.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描. 2.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一 ...

  6. 【uoj#46】 [清华集训2014] 玄学

      题目传送门:uoj46   题意简述:要求在序列上维护一个操作间支持结合律的区间操作,查询连续一段时间内的操作对单点的作用效果,\(n \leq 10^5,m \leq 6 \times 10^5 ...

  7. json-server

    json-server 一个前端模拟数据的本地化服务器 安装 npm install -g json-server 查看是否安装成功 json-server -v 新建一个文件夹 在文件夹中新建db. ...

  8. 轻量化模型之SqueezeNet

    自 2012 年 AlexNet 以来,卷积神经网络在图像分类.目标检测.语义分割等领域获得广泛应用.随着性能要求越来越高,AlexNet 已经无法满足大家的需求,于是乎各路大牛纷纷提出性能更优越的 ...

  9. 网络编程基础之TCP学习(二)编程案例

    TCP网络编程流程如下: 实现功能:服务器端与客户端成功通讯后返回get! 服务器端程序 #include <netdb.h> #include <sys/socket.h> ...

  10. GOLANG的继承+接口语法练习

    继承与接口同时存在 在Golang语言中,可以这么说:接口是继承的功能补充! 武当派有一个徒弟结构体,它继承WuDangMaster结构体的字段及方法 武林之中还有一个泰山北斗,名约少林派,少林入门神 ...