如何构造线程

在运行线程之前需要先构造线程对象,线程对象的构造需要指定线程所需要的属性,比如:所属线程组、线程优先级、是否为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. 刚接触neo4j 问下 neo4j 生成的节点图形可以发布为纯网页方式么

    6 回复 pangguoming 1楼•3 年前 你是想要neo4j web控制端的可视化功能吗? 那是用D3.js 做的,你用前端用D3.js配合Java自己做 或者 去下载neo4j 的前端 开源 ...

  2. 怎样理解Canvas

    Canvas 是一种在网页中的画布, 是一个HTML5新增的标签, 是一种高效的绘制图形的技术, 在JavaScript中有一个专门的API用于给他赋能( CanvasRenderingContext ...

  3. 12-MySQL DBA笔记-MySQL复制

    第12章 MySQL复制 本章将为读者讲述MySQL的复制技术,首先,介绍最基础的主从复制,它是其他所有复制技术的基础,接着再为读者讲述各种复制架构的搭建,最后,列举了一些常见的复制问题及处理方式.复 ...

  4. SQL Prompt 注册后隔一段时间莫名无法使用的处理

    https://blog.csdn.net/anyqu/article/details/88537197 以前一直以为是授权丢了,反复重装也解决不了 Sql Prompt---Unable to co ...

  5. express相关操作

    1.   安装应用生成器npm install express-generator –g 2.   生成项目Express --view=ejs myapp 3.   进入项目安装依赖包 npm in ...

  6. shake.js实现微信摇一摇功能

    项目要求实现点击摇一摇图片,图片摇一摇,并且摇一摇手机,图片也要摇一摇. 关于用js怎样实现摇一摇手机图片摇一摇,我在网络上找了一些方法,真正有用的是shake.js. 接下来,上shake.js源码 ...

  7. 安卓开发之sql语句增删改查

    package com.lidaochen.phonecall; import android.content.Context; import android.database.sqlite.SQLi ...

  8. 如何使用Chrome开发者工具找到Marketing Cloud某个contact的guid

    我们使用nodejs对contact进行修改时,需要指定待修改contact实例的guid. 这个guid属于technical属性,在Marketing Cloud UI上默认情况下不可见.如何找到 ...

  9. ASE19团队项目alpha阶段model组 scrum4 记录

    本次会议于11月6日,19时整在微软北京西二号楼sky garden召开,持续50分钟. 与会人员:Jiyan He, Kun Yan, Lei Chai, Linfeng Qi, Xueqing W ...

  10. MinGW-W64 编译 LLVM 与 Clang

    原文: http://blog.csdn.net/happywjh666/article/details/51415723 编译环境: 系统 --win10 64位 gcc -- version 5. ...