Java中的多线程
Java是一种多线程编程语言,这意味着我们可以使用Java开发多线程程序。多线程程序包含两个或多个可以并发运行的部分,每个部分可以同时处理不同的任务,从而最大限度地利用可用资源,尤其是在您的计算机有多个CPU的情况下。
根据定义,多任务处理是指多个进程共享公共处理资源(例如CPU)。多线程将多任务处理的概念扩展到应用程序中,您可以在其中将单个应用程序内的特定操作细分为单独的线程。每个线程都可以并行运行。操作系统不仅在不同的应用程序之间分配处理时间,还在应用程序中的每个线程之间分配处理时间。
多线程使您能够以一种方式编写程序,其中多个活动可以在同一个程序中并发进行。
线程的生命周期
线程在其生命周期中会经历不同的阶段。例如,线程诞生、启动、运行,然后死亡。下图显示了线程的完整生命周期。
以下是生命周期的阶段:
**新建** - 新线程从新建状态开始其生命周期。它保持在此状态,直到程序启动线程。它也被称为**新生的线程**。
**可运行** - 新生的线程启动后,线程变为可运行状态。处于此状态的线程被认为正在执行其任务。
**等待** - 有时,线程在等待另一个线程执行任务时会过渡到等待状态。线程仅在另一个线程发出信号指示等待线程继续执行时才返回到可运行状态。
**计时等待** - 可运行线程可以进入计时等待状态一段时间。处于此状态的线程在该时间间隔到期或其等待的事件发生时返回到可运行状态。
**终止(死亡)** - 可运行线程在完成其任务或以其他方式终止时进入终止状态。
线程优先级
每个Java线程都有一个优先级,它帮助操作系统确定线程调度的顺序。
Java线程优先级范围在MIN_PRIORITY(常量1)和MAX_PRIORITY(常量10)之间。默认情况下,每个线程都分配NORM_PRIORITY(常量5)优先级。
优先级较高的线程对程序来说更重要,应在优先级较低的线程之前分配处理器时间。但是,线程优先级不能保证线程执行的顺序,并且在很大程度上依赖于平台。
通过实现Runnable接口创建线程
如果您的类旨在作为线程执行,那么您可以通过实现**Runnable**接口来实现这一点。您需要遵循三个基本步骤。
步骤1
第一步,您需要实现**Runnable**接口提供的run()方法。此方法为线程提供了一个入口点,您将在该方法中放置完整的业务逻辑。以下是run()方法的简单语法。
public void run( )
步骤2
第二步,您将使用以下构造函数实例化一个**Thread**对象。
Thread(Runnable threadObj, String threadName);
其中,threadObj是实现**Runnable**接口的类的实例,而**threadName**是赋予新线程的名称。
步骤3
创建Thread对象后,您可以通过调用**start()**方法启动它,该方法会执行对run()方法的调用。以下是start()方法的简单语法。
void start();
示例
以下是一个创建新线程并开始运行它的示例。
class RunnableDemo implements Runnable { private Thread t; private String threadName; RunnableDemo( String name) { threadName = name; System.out.println("Creating " + threadName ); } public void run() { System.out.println("Running " + threadName ); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i); // Let the thread sleep for a while. Thread.sleep(50); } } catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class TestThread { public static void main(String args[]) { RunnableDemo R1 = new RunnableDemo( "Thread-1"); R1.start(); RunnableDemo R2 = new RunnableDemo( "Thread-2"); R2.start(); } }
输出
Creating Thread-1 Starting Thread-1 Creating Thread-2 Starting Thread-2 Running Thread-1 Thread: Thread-1, 4 Running Thread-2 Thread: Thread-2, 4 Thread: Thread-1, 3 Thread: Thread-2, 3 Thread: Thread-1, 2 Thread: Thread-2, 2 Thread: Thread-1, 1 Thread: Thread-2, 1 Thread Thread-1 exiting. Thread Thread-2 exiting.
通过扩展Thread类创建线程
创建线程的第二种方法是创建一个扩展**Thread**类的新的类,使用以下两个简单的步骤。这种方法在处理使用Thread类中可用方法创建的多个线程时提供了更大的灵活性。
步骤1
您需要重写Thread类中可用的**run()**方法。此方法为线程提供了一个入口点,您将在该方法中放置完整的业务逻辑。以下是run()方法的简单语法。
public void run( )
步骤2
创建Thread对象后,您可以通过调用**start()**方法启动它,该方法会执行对run()方法的调用。以下是start()方法的简单语法。
void start( );
示例
以下是重写为扩展Thread的前面程序。
class ThreadDemo extends Thread { private Thread t; private String threadName; ThreadDemo( String name) { threadName = name; System.out.println("Creating " + threadName ); } public void run() { System.out.println("Running " + threadName ); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i); // Let the thread sleep for a while. Thread.sleep(50); } } catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class TestThread { public static void main(String args[]) { ThreadDemo T1 = new ThreadDemo( "Thread-1"); T1.start(); ThreadDemo T2 = new ThreadDemo( "Thread-2"); T2.start(); } }
输出
Creating Thread-1 Starting Thread-1 Creating Thread-2 Starting Thread-2 Running Thread-1 Thread: Thread-1, 4 Running Thread-2 Thread: Thread-2, 4 Thread: Thread-1, 3 Thread: Thread-2, 3 Thread: Thread-1, 2 Thread: Thread-2, 2 Thread: Thread-1, 1 Thread: Thread-2, 1 Thread Thread-1 exiting. Thread Thread-2 exiting.
线程方法
以下是Thread类中可用的一些重要方法。
序号 | 方法及描述 |
---|---|
1 | public void start() 在单独的执行路径中启动线程,然后在此Thread对象上调用run()方法。 |
2 | public void run() 如果此Thread对象是使用单独的Runnable目标实例化的,则在此Runnable对象上调用run()方法。 |
3 | public final void setName(String name) 更改Thread对象的名称。还有一个getName()方法用于检索名称。 |
4 | public final void setPriority(int priority) 设置此Thread对象的优先级。可能的值介于1和10之间。 |
5 | public final void setDaemon(boolean on) 值为true表示此Thread为守护线程。 |
6 | public final void join(long millisec) 当前线程在此线程上调用此方法,导致当前线程阻塞,直到第二个线程终止或指定的毫秒数过去。 |
7 | public void interrupt() 中断此线程,如果它由于任何原因被阻塞,则导致它继续执行。 |
8 | public final boolean isAlive() 如果线程处于活动状态,则返回true,即线程启动后但在运行完成之前。 |
前面的方法是在特定的Thread对象上调用的。Thread类中的以下方法是静态的。调用其中一个静态方法会在当前正在运行的线程上执行操作。
序号 | 方法及描述 |
---|---|
1 | public static void yield() 导致当前正在运行的线程让位于任何其他具有相同优先级的等待调度的线程。 |
2 | public static void sleep(long millisec) 导致当前正在运行的线程至少阻塞指定的毫秒数。 |
3 | public static boolean holdsLock(Object x) 如果当前线程持有给定Object上的锁,则返回true。 |
4 | public static Thread currentThread() 返回对当前正在运行的线程的引用,即调用此方法的线程。 |
5 | public static void dumpStack() 打印当前正在运行的线程的堆栈跟踪,这在调试多线程应用程序时非常有用。 |
示例
以下ThreadClassDemo程序演示了Thread类的一些方法。考虑一个实现**Runnable**的类**DisplayMessage**。
// File Name : DisplayMessage.java // Create a thread to implement Runnable public class DisplayMessage implements Runnable { private String message; public DisplayMessage(String message) { this.message = message; } public void run() { while(true) { System.out.println(message); } } }
以下是扩展Thread类的另一个类。
// File Name : GuessANumber.java // Create a thread to extentd Thread public class GuessANumber extends Thread { private int number; public GuessANumber(int number) { this.number = number; } public void run() { int counter = 0; int guess = 0; do { guess = (int) (Math.random() * 100 + 1); System.out.println(this.getName() + " guesses " + guess); counter++; } while(guess != number); System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**"); } }
以下是主程序,它使用了上面定义的类。
示例
// File Name : ThreadClassDemo.java public class ThreadClassDemo { public static void main(String [] args) { Runnable hello = new DisplayMessage("Hello"); Thread thread1 = new Thread(hello); thread1.setDaemon(true); thread1.setName("hello"); System.out.println("Starting hello thread..."); thread1.start(); Runnable bye = new DisplayMessage("Goodbye"); Thread thread2 = new Thread(bye); thread2.setPriority(Thread.MIN_PRIORITY); thread2.setDaemon(true); System.out.println("Starting goodbye thread..."); thread2.start(); System.out.println("Starting thread3..."); Thread thread3 = new GuessANumber(27); thread3.start(); try { thread3.join(); } catch (InterruptedException e) { System.out.println("Thread interrupted."); } System.out.println("Starting thread4..."); Thread thread4 = new GuessANumber(75); thread4.start(); System.out.println("main() is ending..."); } }
这将产生以下结果。您可以反复尝试此示例,每次都会得到不同的结果。
输出
Starting hello thread... Starting goodbye thread... Hello Hello Hello Hello Hello Hello Goodbye Goodbye Goodbye Goodbye Goodbye .......
主要的Java多线程概念
在Java中进行多线程编程时,您需要掌握以下概念。