其实你问的应该是为什么直接写Thread。
先看下api上如此写:
currentThread
public static Thread currentThread()
返回对当前正在执行的线程对象的引用。
可见这时个静态方法,你这么理解更好点:你在哪个线程调用的我(currentThread),我就给你返回哪个线程。跟父子其实没有关系的,你在父中调用我,我就返回你说的父线程,你在子调用我就返回子线程,你在main主线程调用,我就返回主线程。也就是说你cpu正在运行哪个线程。如图:
t1start(); //表示启动线程,此时线程真正启动起来。Threadsleep(timeout); //表示让当前线程睡眠一段时间。
至于每次结果不一样,很正常,这也是正是多线程的一个特点——不确定性。
itjobJava老师讲过:1)线程堆栈概述及基础知识
2)线程堆栈的生成原理以及相关工具
3)不同JVM线程堆栈的格式的差异(SunHotSpot、IBMJRE、OracalJRockit)
4)线程堆栈日志介绍以及解析方法
5)线程堆栈的分析和相关的技术
6)常见的问题模板(线程竟态、死锁、IO调用挂死、垃圾回收/问题、死循环等)
7)线程堆栈问题实例分析
我希望这一系列的培训能给你带来确实的帮助,所以请持续关注每周的文章更新。
但是如果我在学习过程中有疑问或者无法理解文章中的内容该怎么办?
不用担心,把我当做你的导师就好。任何关于线程堆栈的问题都可以咨询我(前提是问题不能太low)。请随意选择下面的几种方式与我取得联系:
1)直接本文下面发表评论(不好意思的话可以匿名)
2)将你的线程堆栈数据提交到RootCauseAnalysisforum
3)发Email给我,地址是@@hotmail
能帮我分析我们产品上遇到的问题么?
当然可以,如果你愿意的话可以把你的堆栈现场数据通过邮件或论坛RootCauseAnalysisforum发给我。处理实际问题是才是学习提升技能的王道。
我真心期望大家能够喜欢这个培训。所以我会尽我所能去为你提供高质量的材料,并回答大家的各种问题。
在介绍线程堆栈分析技术和问题模式之前,先要给大家讲讲基础的内容。所以在这篇帖子里,我将先覆盖到最基本的内容,这样大家就能更好的去理解JVM、中间件、以及JavaEE容器之间的交互。
JavaVM概述
Java虚拟机是JaveEE平台的基础。它是中间件和应用程序被部署和运行的地方。
JVM向中间件软件和你的Java/JavaEE程序提供了下面这些东西:
_(二进制形式的)Java/JavaEE程序运行环境
_一些程序功能特性和工具(IO基础设施,数据结构,线程管理,安全,监控等等)
_借助垃圾回收的动态内存分配与管理
你的JVM可以驻留在许多的 *** 作系统(Solaris,AIX,Windows等等)之上,并且能根据你的物理服务器配置,你可以在每台物理/虚拟服务器上安装1到多个JVM进程
JVM与中间件之间的交互
下面这张图展示了JVM、中间件和应用程序之间的高层交互模型。
如你所见,标准JavaEE应用程序的线程的分配实在中间件内核与JVM之间完成的。(当然也有例外,应用程序可以直接调用API来创建线程,这种做法并不常见,而且在使用的过程中也要特别的小心)
同时,请注意一些线程是由JVM内部来进行管理的,典型的例子就是垃圾回收线程,JVM内部使用这个线程来做并行的垃圾回收处理。
因为大多数的线程分配都是由JavaEE容器完成的,所以能够理解和认识线程堆栈跟踪,并能从线程堆栈数据中识别出它来,对你而言很重要这可以让你能够快速的知道JavaEE容器正要执行的是什么类型的请求
从一个线程转储堆栈的分析角度来看,你将能了解从JVM发现的线程池之间的不同,并识别出请求的类型
最后一节会向你提供对于HotSopVM而言什么是JVM线程堆栈的一个概述,还有你将会遇到的各种不同的线程而对IBMVM线程堆栈形式详细内容将会在第四节向你提供
请注意你可以从根本原因分析论坛获得针对本文的线程堆栈示例
JVM线程堆栈——它是什么
JVM线程堆栈是一个给定时间的快照,它能向你提供所有被创建出来的Java线程的完整清单
Java多线程的创建及启动
Java中线程的创建常见有如三种基本形式
1继承Thread类,重写该类的run()方法。
复制代码
1 class MyThread extends Thread {
2
3 private int i = 0;
4
5 @Override
6 public void run() {
7 for (i = 0; i < 100; i++) {
8 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
9 }
10 }
11 }
复制代码
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Thread myThread1 = new MyThread(); // 创建一个新的线程 myThread1 此线程进入新建状态
8 Thread myThread2 = new MyThread(); // 创建一个新的线程 myThread2 此线程进入新建状态
9 myThread1start(); // 调用start()方法使得线程进入就绪状态
10 myThread2start(); // 调用start()方法使得线程进入就绪状态
11 }
12 }
13 }
14 }
复制代码
如上所示,继承Thread类,通过重写run()方法定义了一个新的线程类MyThread,其中run()方法的方法体代表了线程需要完成的任务,称之为线程执行体。当创建此线程类对象时一个新的线程得以创建,并进入到线程新建状态。通过调用线程对象引用的start()方法,使得该线程进入到就绪状态,此时此线程并不一定会马上得以执行,这取决于CPU调度时机。
2实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
复制代码
1 class MyRunnable implements Runnable {
2 private int i = 0;
3
4 @Override
5 public void run() {
6 for (i = 0; i < 100; i++) {
7 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
8 }
9 }
10 }
复制代码
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
8 Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
9 Thread thread2 = new Thread(myRunnable);
10 thread1start(); // 调用start()方法使得线程进入就绪状态
11 thread2start();
12 }
13 }
14 }
15 }
复制代码
相信以上两种创建新线程的方式大家都很熟悉了,那么Thread和Runnable之间到底是什么关系呢?我们首先来看一下下面这个例子。
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable();
8 Thread thread = new MyThread(myRunnable);
9 threadstart();
10 }
11 }
12 }
13 }
14
15 class MyRunnable implements Runnable {
16 private int i = 0;
17
18 @Override
19 public void run() {
20 Systemoutprintln("in MyRunnable run");
21 for (i = 0; i < 100; i++) {
22 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
23 }
24 }
25 }
26
27 class MyThread extends Thread {
28
29 private int i = 0;
30
31 public MyThread(Runnable runnable){
32 super(runnable);
33 }
34
35 @Override
36 public void run() {
37 Systemoutprintln("in MyThread run");
38 for (i = 0; i < 100; i++) {
39 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
40 }
41 }
42 }
复制代码
同样的,与实现Runnable接口创建线程方式相似,不同的地方在于
1 Thread thread = new MyThread(myRunnable);
那么这种方式可以顺利创建出一个新的线程么?答案是肯定的。至于此时的线程执行体到底是MyRunnable接口中的run()方法还是MyThread类中的run()方法呢?通过输出我们知道线程执行体是MyThread类中的run()方法。其实原因很简单,因为Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。
1 public interface Runnable {
2
3 public abstract void run();
4
5 }
我们看一下Thread类中对Runnable接口中run()方法的实现:
复制代码
@Override
public void run() {
if (target != null) {
targetrun();
}
}
复制代码
也就是说,当执行到Thread类中的run()方法时,会首先判断target是否存在,存在则执行target中的run()方法,也就是实现了Runnable接口并重写了run()方法的类中的run()方法。但是上述给到的列子中,由于多态的存在,根本就没有执行到Thread类中的run()方法,而是直接先执行了运行时类型即MyThread类中的run()方法。
3使用Callable和Future接口创建线程。具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。
看着好像有点复杂,直接来看一个例子就清晰了。
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4
5 Callable<Integer> myCallable = new MyCallable(); // 创建MyCallable对象
6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象
7
8 for (int i = 0; i < 100; i++) {
9 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
10 if (i == 30) {
11 Thread thread = new Thread(ft); //FutureTask对象作为Thread对象的target创建新的线程
12 threadstart(); //线程进入到就绪状态
13 }
14 }
15
16 Systemoutprintln("主线程for循环执行完毕");
17
18 try {
19 int sum = ftget(); //取得新创建的新线程中的call()方法返回的结果
20 Systemoutprintln("sum = " + sum);
21 } catch (InterruptedException e) {
22 eprintStackTrace();
23 } catch (ExecutionException e) {
24 eprintStackTrace();
25 }
26
27 }
28 }
29
30
31 class MyCallable implements Callable<Integer> {
32 private int i = 0;
33
34 // 与run()方法不同的是,call()方法具有返回值
35 @Override
36 public Integer call() {
37 int sum = 0;
38 for (; i < 100; i++) {
39 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
40 sum += i;
41 }
42 return sum;
43 }
44
45 }
复制代码
首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:
1 public class FutureTask<V> implements RunnableFuture<V> {
2
3 //
4
5 }
1 public interface RunnableFuture<V> extends Runnable, Future<V> {
2
3 void run();
4
5 }
于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。
执行下此程序,我们发现sum = 4950永远都是最后输出的。而“主线程for循环执行完毕”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕”的输出时机是没有任何问题的,那么为什么sum =4950会永远最后输出呢?
原因在于通过ftget()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ftget()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。
你好,本题已解答,如果满意
请点右下角“采纳答案”。
java中线程池的监控可以检测到正在执行的线程数。
通过线程池提供的参数进行监控。线程池里有一些属性在监控线程池的时候可以使用
taskCount:线程池需要执行的任务数量。
completedTaskCount:线程池在运行过程中已完成的任务数量。小于或等于taskCount。
largestPoolSize:线程池曾经创建过的最大线程数量。通过这个数据可以知道线程池是否满过。如等于线程池的最大大小,则表示线程池曾经满了。
getPoolSize:线程池的线程数量。如果线程池不销毁的话,池里的线程不会自动销毁,所以这个大小只增不+ getActiveCount:获取活动的线程数。
通过扩展线程池进行监控。通过继承线程池并重写线程池的beforeExecute,afterExecute和terminated方法,我们可以在任务执行前,执行后和线程池关闭前干一些事情。如监控任务的平均执行时间,最大执行时间和最小执行时间等。这几个方法在线程池里是空方法。如:
protected void beforeExecute(Thread t, Runnable r) { }
以上就是关于java中线程子类获取当前线程的引用时,线程子类调用Thread.currentThread()方法的疑问,谢谢大神。全部的内容,包括:java中线程子类获取当前线程的引用时,线程子类调用Thread.currentThread()方法的疑问,谢谢大神。、java中的线程具体如何运行、你如何在Java中获取线程堆栈等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)