从前面的操作中,我们可以看到无论是实现类 Runable 接口还是继承了 Thread 类,还是实现了 Callable 接口,最终都要通过 Thread 的 start() 方法。所以对线程的操作还是在 Thread 的类中,其主要方法有:
方法名称 | 描述 |
---|---|
public static Thread currentThread() | 返回目前正在执行的线程 |
public final String getName() | 返回线程的名称 |
public final int getPriority() | 返回线程的优先级 |
public boolean isInterrupted() | 返回目前的线程是否被中断,如果是,返回 true,否则返回 false。 |
public final boolean isAlive() | 判断线程是否在活动,如果是返回true,如果不是返回false。 |
public final void setName(String name) | 给当前线程设定名称 |
public void run() | 运行当前线程 |
public static void sleep(long millis) throws InterruptedException | 使当前正在执行的线程休眠 millis 毫秒 |
public void start() | 开始执行线程 |
public static void yield() | 将目前正在执行的线程请求暂停,允许其他的同等优先级的线程获得运行机会 |
public final void join() throws Interrupted Exception | 把指定的线程加入当前线程,可以让两个交替的线程顺序执行 |
public final void setDaemon(boolean on) | 将一个线程设置成后台运行 |
在上面的表格里面我们可以看到获取线程的名称可以用 getName() ,通过 setName() 方法给线程设置名称。线程的名称一般在启动线程之前设置,也允许为已经于心的线程设置名称。允许多个线程拥有相同的名称。但是在真实使用场景中,我们应该避免这样的事情发生。
package com.haicoder.net.thread;
public class ThreadName implements Runnable{
@Override
public void run() {
System.out.println("当前线程名称为:" + Thread.currentThread().getName()); //获取当前线程名称
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
ThreadName threadName = new ThreadName();
Thread runThread = new Thread(threadName);
runThread.setName("线程直接设置名称"); //设置线程名称
runThread.start();
Thread runThread2 = new Thread(threadName,"构造函数设置线程名称"); //构造函数设置线程名称
runThread2.start();
}
}
运行效果图如下:
从上面运行效果可以看出,在设置线程名称的时候,可以用构造方法,也可以直接为当前线程设置名称,给线程设置名称的好处是在真实的生产场景中,可以方便的定位到是什么样的线程做什么样的事情,方便定位问题。
通过前面的讲解我们知道 Thread 的 start() 方法是通知 CPU 这个线程已经准备好启动了,就等 CPU 来调度了,在线程中判断当前的线程是否存活的函数 isAlive() 方法来测试。
package com.haicoder.net.thread;
public class ThreadAlive implements Runnable {
@Override
public void run() {
System.out.println("当前运行着的线程名称为:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Thread currentThread = new Thread(new ThreadAlive(),"判断存活状态线程"); //使用构造方法设置线程名称
System.out.println("线程调度前存活状态 : " + currentThread.isAlive());
currentThread.start();
System.out.println("线程调度后存活状态:" + currentThread.isAlive());
}
}
运行效果如下:
从运行结果图中我们可以看到,在调用线程的 start() 方法之前判断线程的状态时,不是存活的,而调用了 start() 方法之后就变成了存活的状态。
在线程的执行过程中,我们可以使用 join() 方法来让一个线程强制插队,强制执行,这个线程在执行过程中其他的线程无法执行,必须等该线程执行完才能执行。
package com.haicoder.net.thread;
public class JoinThread implements Runnable{
@Override
public void run() {
System.out.println("当前执行的线程名称为 :" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Thread thread1 = new Thread(new JoinThread(),"Thread - 01");
thread1.start();
Thread thread2 = new Thread(new JoinThread(),"Thread - 02");
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main 线程运行 " + Thread.currentThread().getName() );
}
}
从上面运行效果中我们可以看到最后的 main 线程始终最后执行打印, thread2 线程调用 join() 方法,会将 main 线程挂起,等 Thread - 02 执行结束之后才会执行 main 线程方法。
线程在执行过程中,如果先要进行短暂的阻塞,等自己执行完之后再执行后面的流程,就可以用线程的 sleep() 方法。线程的休眠是不释放 cpu 资源的,即它不释放,其他的线程是不能够获取到被当前线程占用的 cpu 的调度。
package com.haicoder.net.thread;
public class SleepThread implements Runnable {
@Override
public void run() {
System.out.println("调用前的时间点:" + System.currentTimeMillis());
try {
System.out.println("注意咯,我要睡觉咯!");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("调用后点时间点:" + System.currentTimeMillis());
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Thread sleepThread = new Thread(new SleepThread(),"Sleep-Thread");
sleepThread.start();
}
}
运行结果如下:
在线程执行过程中,我们在 run 方法里面调用了 sleep 方法,让该线程休息了 2 秒,在 sleep 的方法中后面的打印输出需要等待差不多 2 秒钟的时间。在真实使用场景中,如果我们后面的一个线程需要前一个线程的执行结果,不考虑性能的情况下,可以考虑使用 sleep 方法来处理。
当运行一个线程当时候,如果想终止状态,或者不继续运行,该怎么做呢?我们可以调用线程的 interrupt() 方法来终止线程。
package com.haicoder.net.thread;
public class InterruptThread implements Runnable {
@Override
public void run() {
System.out.println("1 进入 run 方法");
try {
Thread.sleep(10000);
System.out.println("2 已经休眠结束");
} catch (Exception e) {
System.out.println("3 休眠被终止");
return;
}
System.out.println("4 run 方法正常结束");
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
InterruptThread myThread = new InterruptThread();
Thread thread01 = new Thread(myThread,"Thread 01");
thread01.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
thread01.interrupt();
}
}
运行效果如下:
在 catch 方法体里面,我们直接 return ,线程执行结束了。
后台线程是指即使当前 java 的进程结束了,还有一个后台线程会继续执行。比如我们了解到 java 垃圾收集器就是一个后台线程。设置后台线程的方法是 setDaemon() 方法。
package com.haicoder.net.thread;
public class DaemonThread implements Runnable {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "在运行");
}
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Thread thread01 = new Thread(new DaemonThread());
thread01.setDaemon(true);
thread01.start();
}
}
运行效果如下图:
我们写了一个死循环,但是当前的操作还是执行完了,我们将调用死循环的线程设置为后台线程。
线程的生命周期 中我们了解到所有的线程在执行之前都是就绪状态,如果这个时候有多个线程在就绪状态,那么哪个线程会优先执行呢?线程这边有优先级的概念,哪个线程的优先级高,就会执行哪个线程。(一般情况下会这样)。在 java 中可以使用 setPriority() 方法进行优先级设置。
定义 | 描述 | 表示的常量 |
---|---|---|
MIN_PRIORITY | 最低优先级 | 1 |
NORM_PRIORITY | 中等优先级,线程的默认优先级 | 5 |
MAX_PRIORITY | 最高优先级 | 10 |
package com.haicoder.net.thread;
public class PriorityThread implements Runnable {
@Override
public void run() {
for (int i=0;i<3;i++){
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行 " + i);
}
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Thread thread01 = new Thread(new PriorityThread(),"Thread 01");
Thread thread02 = new Thread(new PriorityThread(),"Thread 02");
Thread thread03 = new Thread(new PriorityThread(),"Thread 03");
thread01.setPriority(Thread.MIN_PRIORITY);
thread02.setPriority(Thread.NORM_PRIORITY);
thread03.setPriority(Thread.MAX_PRIORITY);
thread01.start();
thread02.start();
thread03.start();
}
}
从程序的运行结果中可以观察到,线程将根据其优先级的大小来决定哪个线程会先运行,但是并不是哪个线程的优先级越高就一定会先执行,哪个线程的执行还是靠 CPU 来决定。
在线程执行过程中,我们可以使用 yield() 方法让当前线程先暂停,让其他线程执行,等其他线程执行完再执行当前线程。
package com.haicoder.net.thread;
public class YieldThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
if(i == 3){
System.out.print(Thread.currentThread().getName() + " 线程礼让: " );
Thread.currentThread().yield();
}
System.out.println(Thread.currentThread().getName() + " 运行 : " + i);
}
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
YieldThread yieldThread = new YieldThread();
Thread thread01 = new Thread(yieldThread,"Thread 01");
Thread thread02 = new Thread(yieldThread,"Thread 02");
thread01.start();
thread02.start();
}
}
从上面运行效果可以看到,每当线程满足条件 i == 3 的时候,就会将本线程暂停,让其他的线程先执行。