这篇文章介绍Thread类的方法,包含Thread类的静态方法和实例方法,有关yield、sleep和Object类的wait方法的比较放在Lock里对比介绍。

1、run()和start()

这两个方法的对比在《创建线程的方法》里的Thread类里介绍了。

2、yield()

Thread类的静态方法,调用后能让当前线程释放CPU的时间片,进入就绪状态(而非阻塞状态),让与该线程有同等优先级的其他线等待线程获取CPU执行权,也有可能当前线程又重新获得CPU时间片进入运行状态,调用yield方法不会使线程释放它所持有的对象的同步锁。

3、sleep(sec)

Thread类的静态方法,调用后能使线程由运行状态进入休眠阻塞状态。入参为休眠时间,单位为毫秒,超过休眠时间后,线程会由休眠阻塞状态进入就绪状态,等待CPU时间片重新进入运行状态。sleep方法不会释放当前线程所持有的的对象的锁。

4、中断

java中断相关的有3个方法,stop()方法已经不推荐使用了。
void interrupt()

  • Thread类实例方法,向线程发送中断请求,将线程的中断状态置为true,但不会中断(停止)这个正在运行的线程,类似“set”。
  • 当线程处于阻塞状态(比如调用了sleep方法),此时再调用该线程的interrupt()方法,会抛出InterruptedException中断异常,不会将线程的中断状态再置为true。

boolean isInterrupted()

  • Thread类的实例方法,用来返回线程的中断状态,调用这一方法不会改变线程的中断状态,类似“get”。

static boolean interrupted()
Thead类的静态方法,返回线程的中断状态,同时会产生副作用:将线程的中断状态置为false,类似“get”+”set”。

从上面的叙述可以看出,这三个方法并不能真正的将一个线程中断,只能改变线程的中断状态(boolean值),改变了线程的中断状态后,再由实际代码判断到底要不要停止当前线程(return掉也行),因此这个中断状态可以被用来当做标志位(开关),我们可以通过if或者while这种判断语句来决定线程中断状态置为true后该怎么处理,举个例子:

  1. public class MyThread extends Thread{
  2. @Override
  3. public void run() {
  4. while (!this.isInterrupted())
  5. {
  6. System.out.println("当前线程没有被中断,继续干活");
  7. }
  8. System.out.println("当前线程被被中断,停止干活");
  9. }
  10. }
public class ConcurrentOneMain {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        t.interrupt();
    }
}

上面程序中,MyThread类里通过while(!this.isInterrupted())来对中断状态置为true的线程处理,当中断状态为true,跳出while循环,打印”当前线程被被中断,停止干活”,当为false时继续执行while循环体里语句,打印”当前线程没有被中断,继续干活”。main方法里主线程会先休眠5秒,再对MyThread实例线程进行中断,运行结果如下:

...
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程没有被中断,继续干活
当前线程被被中断,停止干活

开始的5秒内MyThread线程运行run()方法,循环打印“继续干活”,主线程对MyThread线程调用interrupt方法后,将MyThread线程t的中断状态置为true,结束while循环,打印“停止干活”,然后MyThread线程t的run()方法执行结束。
当MyThread线程t处于休眠阻塞状态时,主线程对其调用interrupt方法,会抛出InterruptedException,举个例子:

public class MyThread extends Thread{
    @Override
    public void run() {
        while (!this.isInterrupted())
        {
            System.out.println("当前线程没有被中断,继续干活");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e)
            {
                this.interrupt();
            }
        }
        System.out.println("当前线程被被中断,停止干活");
    }
}

修改上面的MyThread类,main方法不变,在while循环里给每次循环sleep一秒,模拟当MyThread类的实例线程t正在sleep(1000)时,主线程给t interrupt了。这时会抛出InterruptedException异常,但是不会将MyThread类的实例t的中断状态置为true,因此在catch子句里还要对线程t进行interrupt,主动将t的中断状态置为true,这是才能跳出while循环 ,结束run()方法。

5、join()/join(sec)

Thread类的实例方法,t.join()方法阻塞调用此方法的线程,直到线程t完成,此线程再继续,可以将程序由异步执行转变为串行执行。通常用于让主线程等待子线程运行后再执行。
举个例子:

public class MyThread extends Thread{
    @Override
    public void run() {
        String currentThreadName = Thread.currentThread().getName();
        System.out.println(currentThreadName + "开始运行");
        for(int i = 0; i < 20; ++i)
        {
            System.out.println( currentThreadName + "正在运行 " + String.valueOf(i));
        }
    }
}
public class ConcurrentOneMain {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        System.out.println("主线程开始运行");
        for(int i = 0; i < 20; ++i)
        {
            System.out.println("主线程正在运行 " + String.valueOf(i));
        }
    }
}

上面是个异步执行的例子,MyThread t和主线程各自执行各自的 ,结果如下:

...
主线程正在运行 15
Thread-0正在运行 14
主线程正在运行 16
Thread-0正在运行 15
主线程正在运行 17
Thread-0正在运行 16
主线程正在运行 18
Thread-0正在运行 17
主线程正在运行 19
Thread-0正在运行 18
Thread-0正在运行 19

但当在主线程里调用t.join()方法后,主线程会先等待t线程执行完,再执行主线程里的方法,main方法如下:

public class ConcurrentOneMain {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        try{
            t.join();
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        System.out.println("主线程开始运行");
        for(int i = 0; i < 20; ++i)
        {
            System.out.println("主线程正在运行 " + String.valueOf(i));
        }
    }
}

结果如下,将异步执行转换为串行执行:

...
Thread-0正在运行 14
Thread-0正在运行 15
Thread-0正在运行 16
Thread-0正在运行 17
Thread-0正在运行 18
Thread-0正在运行 19
主线程开始运行
主线程正在运行 0
主线程正在运行 1
主线程正在运行 2
主线程正在运行 3
主线程正在运行 4
主线程正在运行 5
...

6、Thread类的其他方法

currentThread()
Thread类的静态方法,返回当前线程的实例对象。
getID()
用来得到线程ID。
getName和setName
用来得到或者设置线程名称。
getPriority和setPriority
用来获取和设置线程优先级。
setDaemon和isDaemon
用来设置线程是否成为守护线程和判断线程是否是守护线程。

参考

Java多线程(六)—线程让步 - 平凡希 - 博客园 www.cnblogs.com