以下内容引用自http://wiki.jikexueyuan.com/project/java/multithreading.html:
Java是一种多线程编程语言,这意味着能用Java开发多线程程序。一个多线程程序包含两个或更多的能并行运行的部分,并且每一部分能最优利用可用资源,尤其是当计算机有多个CPU时,同时解决不同的任务。
多任务处理表示多个过程共同处理像CPU这样共享的资源时。多线程将多任务处理的思想扩展到应用程序,可以将一个单独的应用中的特定的操作细分为单独的线程。每一个线程能并行地运行。操作系统不仅在不同的应用程序中划分处理时间,而且在一个应用程序中的每一个线程中也是如此。
多线程可以用一种多个活动能并行地在同一个程序中进行的方法编写程序。
一、线程的生命周期
一个线程在它的生命周期中通过不同的阶段。例如,一个线程生成,开始,运行,然后死亡。下列的图表展示了一个线程的完整的生命周期。
旧版:
新版:
上述提到的阶段在这解释:
- new: 一个新的线程以一个新的状态开始了它的生命周期。它始终留在这个状态中直到程序开始线程。它也被称为一个生成的进程。
- Runnable: 在一个新生成的线程开始后,这个线程变得可运行。在这个状态下的线程被认为正在执行任务。
- Waiting: 有时候,一个线程当它等待另一个线程工作时跃迁到等待状态。一个线程仅当另一个线程发信号给等待的线程继续执行才跃迁回可运行转态。
- Timed Waiting: 一个可运行的线程能进入定时等待状态等待指定的时间间隔。在这种转态下的线程当时间间隔死亡或者当它所等待的活动发生时跃迁回可运行状态。
- Terminated(Dead): 一个可运行的线程,当它完成了它的任务后进入 terminated 状态,否则它就结束。
二、线程优先级
每一个Java线程有一个帮助操作系统决定线程调度顺序的优先级。
Java线程的优先级在MIN_PRIORITY(一个为1的常数)和MAX_PRIORITY(一个为10的常数)的范围内。缺省状况下,每一个线程给予优先级NORM_PRIORITY(一个为5的常数)。
拥有更高优先级的线程对于一个程序来说更加重要,应当在低优先级的线程前被分配处理时间。然而,线程优先级不能保证线程执行和所依赖的平台。
三、通过实现Runnable接口创建线程
如果一个类想要作为一个线程被执行,那么可以通过实现Runnable接口来到达这个目的。将需要遵从三个基本步骤:
步骤一:
作为第一步需要实现由Runnable接口提供的run()方法。这个方法为线程提供了进入点并且将把完全的业务逻辑放入方法中。下列是简单的run()方法语法:
public void run( )
步骤二:
在第二步将使用以下的构造函数实例化一个 Thread 对象:
Thread(Runnable threadObj, String threadName);
threadObj是实现Runnable接口的类的一个实例,threadName是给新线程的名字。
步骤三:
一旦Thread对象被创建,可以通过调用run()方法的start()方法来开始它。以下是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类中使用可行方法创建的多线程的问题上提供了更多的灵活性。
步骤一:
将需要覆写Thread类中可用的run()方法。这个方法为线程提供入口并且将把完全的业务逻辑放入方法中。以下是run()方法的简单的语法。
public void run( )
步骤二:
一旦Thread对象被创建,可以通过调用run()方法的start()方法来开始它。以下是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方法
以下是在Thread类中可以获得的重要方法的列表。
接口 | 描述 |
---|---|
Methods with Description | 在一个独立的执行路径中开始一个线程,然后在这个Thread对象上调用 run() 方法。 |
public void run() | 如果这个Thread对象是使用一个单独的Runnable目标实例化的,run()方法被Runnable对象调用。 |
public final void setName(String name) | 改变Thread对象的名字。也有一个getName()方法来检索名字。 |
public final void setPriority(int priority) | 设置Thread对象的优先级。可能的值在1到10之间。 |
public final void setDaemon(boolean on) | 一个真值将这个线程标志为守护进程。 |
public final void join(long millisec) | 当前进程在第二个线程上调用这个方法,使得当前进程阻塞直到第二个线程终结或者指定的毫秒数过去。 |
public void interrupt() | 中断这个进程,如果由于任何原因而阻塞,使得它也继续执行。 |
public final boolean isAlive() | 如果线程是活的,返回真值,可在线程已经开始但在运行到完成之前的任何时间。 |
以前的方法是被一个特殊的Thread对象调用的。以下在Thread类中的方法是静态的。调用静态方法会在当前运行的线程上执行操作。
接口 | 描述 |
---|---|
public static void yield() | 使得当前正在运行的线程让步于任何其他相同优先级的正在等待调度的线程。 |
public static void sleep(long millisec) | 使当前运行的线程阻塞至少指定的毫秒数。 |
public static boolean holdsLock(Object x) | 如果当前线程持有给定对象的锁,返回真值。 |
public static Thread currentThread() | 返回对当前运行的线程的引用,也就是调用这个方法的线程。 |
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
.......
测试工程:https://github.com/easonjim/5_java_example/tree/master/javabasicstest/test28