Java中Thread类详解及常用的方法
在Java中,Thread
类是用来实现多线程编程的核心类。每个Java应用程序都至少有一个线程,这个线程是由JVM(Java 虚拟机)创建的,并且负责程序的主方法的执行。不仅如此,除了主线程,Java应用程序可以有其他线程,这些线程可以是由主线程或其他线程创建的,Java 中的 Thread
类就是用于实现这些线程的。
创建并启动一个线程
创建Thread对象的第一种方法是实现Runnable
接口。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running.");
}
}
public class Test {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
以上代码展示了第一种方法的实现。可以看到,我们首先定义了一个实现了Runnable
接口的类 MyRunnable
。在这个类中,我们实现了run()
方法,并在其中写下了我们想让线程执行的代码。接着,我们创建了一个 MyRunnable
的实例,并将其作为参数传递给Thread
类的构造函数。最后,我们调用 start()
方法开始执行该线程。
创建Thread对象的第二种方法是继承Thread
类。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread is running.");
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
从以上代码中,我们可以看到,MyThread
类继承了 Thread
类,并实现了run()
方法。在主方法中,我们创建了一个 MyThread
的实例,并直接调用它的start()
方法开始执行该线程。
线程方法
start()
start()
方法用来启动线程,调用该方法使得线程进入就绪状态。当线程获得 CPU 时间片后,就开始执行 run()
方法。
join()
当一个线程调用另一个线程的join()
方法时,调用线程将被阻塞,直到被调用线程执行完为止。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyRunnable is finished.");
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
System.out.println("Main thread is running.");
thread.join();
System.out.println("Main thread is finished.");
}
}
以上代码中, join()
方法被调用后,主线程将被阻塞,直到线程 thread
执行完后,主线程才会继续执行。
yield()
在一个多线程应用中,线程运行时常常需要等待某个事件的发生,但并不能确定该事件究竟要等多少时间。在这种情况下,可以使用 yield()
方法来使得线程放弃当前的 CPU 时间片,让其它线程运行。
class MyRunnable1 implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable1 is running.");
Thread.yield();
System.out.println("MyRunnable1 is finished.");
}
}
class MyRunnable2 implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable2 is running.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyRunnable2 is finished.");
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
MyRunnable1 myRunnable1 = new MyRunnable1();
MyRunnable2 myRunnable2 = new MyRunnable2();
Thread thread1 = new Thread(myRunnable1);
Thread thread2 = new Thread(myRunnable2);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Main thread is finished.");
}
}
当 MyRunnable1
线程执行到 yield()
方法时,其它线程将有机会获得 CPU 时间片。
sleep()
sleep()
方法让当前正在执行的线程休眠指定的时间,在这段时间内,线程暂时释放CPU控制权,其他线程得以运行。sleep()
方法会抛出一个异常InterruptedException,所以在使用sleep()方法时通常要捕获这个异常。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyRunnable is finished.");
}
}
public class Test {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
以上代码中, MyRunnable
线程在执行到Thread.sleep(2000)
方法时将会休眠2秒钟。
线程状态
一个线程在它的生命周期中可能处于以下五个状态的任意一个状态。
- 新建状态(New):刚刚创建一个线程对象时,它处于新建状态
- 就绪状态(Runnable):当调用start()方法后,线程进入就绪状态
- 运行状态(Running):当就绪状态的线程被调度并获得CPU执行时间,它就进入运行状态
- 阻塞状态(Blocked)或等待状态(Waiting)或计时等待状态(Time Waiting):当线程执行一个同步方法时,线程因为不能获取到所需的锁而进入阻塞状态;线程调用了wait()方法,进入等待状态;线程调用了sleep()方法或调用了带有超时参数的方法,进入计时等待状态。
- 终止状态(Terminated):当线程执行完毕或者发生了一个未捕获的异常并被有效地处理后,线程处于终止状态。
示例说明
以下示例将创建两个线程,并展示它们的不同状态。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread is running.");
System.out.println("MyThread state is " + this.getState().toString());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread is finished.");
System.out.println("MyThread state is " + this.getState().toString());
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
System.out.println("Thread1 state is " + myThread1.getState().toString());
System.out.println("Thread2 state is " + myThread2.getState().toString());
myThread1.start();
myThread2.start();
System.out.println("Thread1 state is " + myThread1.getState().toString());
System.out.println("Thread2 state is " + myThread2.getState().toString());
}
}
以上代码中,我们创建了两个 MyThread
线程,并在主方法中获取了它们的状态。然后,我们启动了这两个线程,并再次获取它们的状态。最终,我们顺序等待这两个线程执行完成后,再次获取它们的状态。
输出:
Thread1 state is NEW
Thread2 state is NEW
MyThread is running.
Thread1 state is RUNNABLE
Thread2 state is RUNNABLE
MyThread is running.
MyThread state is RUNNABLE
Thread1 state is TIMED_WAITING
Thread2 state is RUNNABLE
MyThread is finished.
MyThread state is TERMINATED
Thread1 state is TERMINATED
Thread2 state is TIMED_WAITING
MyThread is finished.
MyThread state is TERMINATED
Thread2 state is TERMINATED
可以看到,线程在被创建后,初始状态为 NEW
;在调用了 start()
方法后,状态变为了 RUNNABLE
。在一个线程正在执行时,状态为 RUNNING
;在一个线程正在等待获取一个锁的时候,状态为 BLOCKED
。而当一个线程执行 wait()
方法时,线程会进入等待状态,状态为 WAITING
;当线程调用 sleep()
方法或带有超时参数的方法时,进入计时等待状态,状态为 TIMED_WAITING
。对于已经完成工作的线程,其状态为 TERMINATED
。
另外,需要注意的是,getState()
方法不是同步的。如果它被调用时线程正在运行,并且线程的状态正在变化,那么可能会无法获取到准确的状态。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中Thread类详解及常用的方法 - Python技术站