currentThread() 方法用来返回代码段正在被哪个线程调用,它是 Thread 类提供的一个 native 方法,返回一个 Thread 类的实例对象,源码如下:
public static native Thread currentThread();
废话就不多说了,直接上代码:
public class Run {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
// 第二个参数为线程的名字
Thread thread = new Thread(myRunnable, "Thread-itming");
thread.start();
}
}
class MyRunnable implements Runnable {
public MyRunnable() {
System.out.println("调用构造方法的线程:" + Thread.currentThread().getName());
}
@Override
public void run() {
System.out.println("调用 run() 方法的线程:" + Thread.currentThread().getName());
}
}
控制台输出如下:
调用构造方法的线程:main
调用 run() 方法的线程:Thread-itming
从输出结果可以看到,调用构造方法的线程是 main 线程,即主线程,调用 run() 方法的线程是新创建的线程 Thread-itming。
在调用 start() 方法之前,所有的代码都是由主线程调用执行的,而在调用 start() 方法之后才会开启一个新的线程,并执行 run() 方法。
这里我们可以思考一个问题,调用 run() 方法和 start() 方法的区别是什么?
为了验证这一点,我对上面的代码做了一些小调整,代码如下:
public class Run {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
// 第二个参数为线程的名字
Thread thread = new Thread(myRunnable, "Thread-itming");
// thread.start();
thread.run();
}
}
class MyRunnable implements Runnable {
public MyRunnable() {
System.out.println("调用构造方法的线程:" + Thread.currentThread().getName());
}
@Override
public void run() {
System.out.println("调用 run() 方法的线程:" + Thread.currentThread().getName());
}
}
控制台输出如下:
调用构造方法的线程:main
调用 run() 方法的线程:main
从输出结果可以看到,调用构造方法和 run() 方法的线程都是 main 线程,由此可以证明直接调用 run() 方法不会启动新线程,需要调用 start() 方法才会启动新的线程。
isAlive() 方法用来判断当前线程是否处于存活状态,存活状态指的是线程已经启动且尚未终止的状态。
下面我们来写一个案例进行测试,代码如下:
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
System.out.println("begin = " + myThread.isAlive());
myThread.start();
System.out.println("end = " + myThread.isAlive());
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("run = " + this.isAlive());
}
}
控制台输出如下:
begin = false
end = true
run = true
这里我们需要注意一点,对于代码:
System.out.println("end = " + myThread.isAlive());
其输出值是不确定的(虽然不确定,但大概率返回 true),输出 true 或 false 取决于执行该行代码时 myThread 线程是否执行完毕,未执行完毕的话就返回 false,执行完毕的话就返回 true。
我们可以代码进行一些修改,让该行代码大概率输出 false,代码如下:
package t004;
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
System.out.println("begin = " + myThread.isAlive());
myThread.start();
/**
* 让当前线程休眠 1000 毫秒,这里的当前线程指的是 main 线程
* 在这 1000 毫秒内,myThread 线程大概率已经执行完毕
*/
Thread.sleep(1000);
System.out.println("end = " + myThread.isAlive());
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("run = " + this.isAlive());
}
}
控制台输出如下:
begin = false
run = true
end = false
sleep() 方法可以让当前线程进入超时等待状态(TIME_WAITING),并在指定时间后恢复到运行状态(RUNNABLE)。它有两个重载的方法,部分源码如下:
public static native void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
sleep(long millis):参数 millis 的单位是毫秒。
sleep(long millis, int nanos):参数 millis 的单位是毫秒,参数 nanos 的单位是纳秒,线程等待的时间是两个参数的和。
getId() 方法用于获取线程的唯一标识。
下面通过一个示例进行说明,代码如下:
public class Test {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " " + thread.getId());
}
}
控制台输出如下:
main 1
yield() 方法的作用是让当前线程释放 CPU 资源,并且当前线程会从运行中状态变为就绪状态(在 Java 中,运行中状态和就绪状态都属于运行状态),然后等待系统调度。
举个例子:有一群小朋友排队等待荡秋千,此时正在荡秋千的甲忽然说我愿意让出秋千,然后我们再一起竞争。最后的结果可能是其他小朋友获得了荡秋千的机会,也可能依然是甲获得了荡秋千的机会。
下面我们来编写一段代码,测试一下 yield() 方法的使用效果,代码如下:
public class Run {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
long count = 0;
for (int i = 0; i < 100000000; i++) {
// Thread.yield();
count = count + i;
}
long endTime = System.currentTimeMillis();
System.out.println("耗时 " + (endTime - beginTime) + " 毫秒");
}
};
thread.start();
}
}
控制台输出如下:
耗时 29 毫秒
然后我们去掉注释,再次运行,控制台输出如下:
耗时 11008 毫秒
我们可以看到去掉注释前后这段代码运行所耗费的时间差距是非常大的,这是因为去掉注释后每一次 for 循环当前线程都会释放所占用的 CPU 资源,然后等待系统的重新调度,所以耗费的时间比较长。