概述
提到Java线程的话,无非就是Runnable、Thread、ThreadGroup了。ThreadGroup是记录了一些线程组中的信息,线程组的名称了、线程组的活跃线程数量了等等,我们今天重点说一下Thread这个类中的方法。
Runnable是提供了线程运行的基础方法(也就是run方法)接口,而Thread才是操作真正线程的类,然而Thread中也有run方法,大家可以看下,这个run方法也是实现了Runnable接口中的,所以,如果你只是想实现一个线程运行的目标(target)就仅实现Runnable接口,如果你想启动线程、终止线程等就extends吧。接下来我们去看下Thread类中的方法。
不知道大家有看java帮助文档的习惯没,我个人挺喜欢看帮助文档的,大致了解一下类、接口的功能。
以下帮助文档使用的是1.6的,源码使用的1.8的源码。
1、我们可以看到Thread类继承自Object类,说明Thread中有Object中的方法
2、Java允许多线程的执行
3、每个线程都有优先级之分(优先级取决去创建该线程的当前线程的优先级),每个线程都可以标记为守护线程和非守护线程(创建该线程的当前线程是守护线程和非守护线程)
4、Java创建线程有两种方法
我们去看下Thread源码中的执行方法(还是先看帮助文档,在去研究源码中的具体方法):
1、Thread类中的嵌套类(Thread.State-线程状态。Thread.UncaughtExceptionHandler-异常未捕获时执行的接口)。我们可以看到有State记录线程状态,有程序可以处理线程出现异常情况
2、我们可以看到有线程的最大优先级、最小优先级以及默认优先级
3、就是一些构造方法了,有各种各样的构造方法。(这些构造方法可以自行去查看内容)
接下来是我们的重点了,我们的Thread中有那些方法,我们可以拿来干什么?
方法太多了,只截取了一部分。我们把主要的方法领出来说明一下:
1、activeCount-返回当前线程的线程组中的活动线程数目
public static int activeCount() {
//我们可以看到源码是获取了当前线程所在线程组,从而获取到活动线程数目
return currentThread().getThreadGroup().activeCount();
}
2、getId、getName、getPriority。获取线程id、线程名称、线程优先级等三个方法,我们平时基本用的时候没有初始化过这三个参数吧,我们看下源码是怎么帮我们分配的这些参数吧。
我们可以看到我们新构造Thread时,系统帮我们生成了线程id(内部维护了一个int值)、线程名称(Thread-数字)、把当前正在运行的线程守护还是非守护设置给新线程(当前线程是守护线程则新线程也为守护线程)、当前正在运行的线程的优先级设置给新线程(当前正在运行的线程优先级是多少,新线程的优先级是多少)、把当前正在运行的线程的线程组设置给新线程(当前线程和新线程同在一个线程组中)
//我们平常最常写的创建线程的方式
public Thread(Runnable target) {
//内部执行了init方法
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
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 */
//设置了线程id
tid = nextThreadID();
}
3、interrupt(中断线程)、interrupted(测试线程是否中断)。这两个方法没什么好说的就是中断线程的,这里说出来只是因为又一次面试官问我:如果停止一个线程?我就知道一个抛出异常,尴尬了
4、setUncaughtExceptionHandler(设置该线程由于未捕获到异常而突然终止时调用的处理程序。线程抛出异常时,你希望执行的程序)。比如你有一个转账的线程,因为数据库操作异常了,你希望将这条异常数据记录下来,则将你的保存记录的代码写到这个程序中
5、join、join(long millis)、join(long millis, int nanos)、sleep、sleep(long millis)、sleep(long millis, int nanos)以及yield()方法。网上有很多解释,我这里在简单说一下。
thread.join方法是等待该线程结束,也就是当前线程不往下执行,等thread这个线程执行完才继续执行,可以用来控制线程执行顺序。
Thread.sleep()使当前线程睡眠、睡眠一段时间。不释放对象锁,仅仅是等待
Thread.yield()暂停当前正在执行的线程对象,并执行其他线程。关键之一就是此方法使得对象锁释放,也就是说拥有对象锁权利的线程都可能执行(包括此线程,因为他也有执行对象的权利)。
最后
以上就是专注诺言为你收集整理的Java基础之线程介绍篇的全部内容,希望文章能够帮你解决Java基础之线程介绍篇所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复