多线程(Multithread)指的是在单个进程中同时运行多个不同的线程,执行不同的任务。多线程意味着一个程序的多行语句块并发执行。
一、实现多线程
1.通过继承Thread类实现多线程。
Thread类来自java.lang包,在Thread类中定义了run()方法,想要实现多线程,必须覆写run()方法。然后使用该类的对象调用start()方法,来激活一个线程。
1 class ThreadDemo extends Thread
2 {
3 public void run()
4 {
5 for(int i=0;i<2;++i)
6 {
7 System.out.println("ThreadDemo在运行!");
8 try
9 {
10 Thread.sleep(1000);
11 }
12 catch(InterruptedException e)
13 {
14 e.printStackTrace();
15 }
16 }
17 }
18 }
19
20 public class ThreadTest
21 {
22 public static void main(String[] args)
23 {
24 new ThreadDemo().start();//激活一个新的线程
25 for(int j=0;j<2;++j)
26 {
27 System.out.println("main方法在运行!");
28 try
29 {
30 Thread.sleep(1000);//睡眠1s
31 }
32 catch(InterruptedException e)
33 {
34 e.printStackTrace();
35 }
36 }
37 }
38 }
输出结果:
main方法在运行!
ThreadDemo在运行!
main方法在运行!
ThreadDemo在运行!
上述例子中的InterruptedException,表示中断异常类,Thread.sleep()和Object.wait()都可以抛出这类中断异常,printStackTrace()方法输出异常信息,这样就可以很清楚的看到两个线程交替执行的结果。如果去掉异常处理语句,那么运行结果如下:
main方法在运行!
main方法在运行!
ThreadDemo在运行!
ThreadDemo在运行!
这个运行结果貌似不是多线程并发执行,但事实上因为循环次数过少,线程运行并没有超过时间片t,所以先把main方法执行的主线程的for循环执行完毕,再转去执行ThreadDemod的线程。(具体的会在第二部分线程的状态中叙述)
2.通过Runnable接口实现多线程。
因为接口可以实现多继承的原因,Runnable接口实现多线程机制更加常用。
1 class RunnableDemo implements Runnable
2 {
3 public void run()
4 {
5 for(int i=0;i<2;++i)
6 {
7 System.out.println("RunnableDemo在运行!");
8 try
9 {
10 Thread.sleep(1000);
11 }
12 catch(InterruptedException e)
13 {
14 e.printStackTrace();
15 }
16 }
17 }
18 }
19
20 public class ThreadTest
21 {
22 public static void main(String[] args)
23 {
24 RunnableDemo r = new RunnableDemo();
25 new Thread(r).start();//使用Thread类的start()方法启动线程
26 for(int i=0;i<2;++i)
27 {
28 System.out.println("main方法在运行!");
29 try
30 {
31 Thread.sleep(1000);
32 }
33 catch(InterruptedException e)
34 {
35 e.printStackTrace();
36 }
37 }
38 }
39 }
值得一提的是,Runnable接口中只有一个run()方法,所以激活一个新线程仍然使用Thread类的start()方法。
new Thread(r).start();Thread类的构造方法,可以将一个Runnable接口(及其子类)的实例化对象作为参数去实例化Thread类对象。
3.两种多线程实现机制的联系与区别
联系:Thread类实现Runnable接口,即Thread类是Runnable的一个子类。
区别:Thread类很难实现资源共享,每个Thread实例都是在独自运行自己的线程,但能通过静态变量实现资源共享;Runnable接口可以直接达到资源共享的目的。
***注意:事实上,上述两个示例程序的运行结果都不唯一,这个错误就是和线程运行的时间片和相关临界区有关。
二、线程的状态
每个Java程序都有一个默认的主线程,对于Java应用程序,主线程是main方法执行的线程。要想实现多线程,必须在主线程中创建新的线程对象。
1.线程具有5种状态:创建、就绪、运行、阻塞、终止。关系如下图:
创建:ThreadDemo t = new ThreadDemo();
就绪:t.start();
运行:执行run()方法。
阻塞:暂时停止执行,原因可能是:调用sleep()、调用wait()、发生I/O阻塞、调用join()方法、不能获得对象锁。
终止:线程执行完毕。
2.线程的优先级
Thread类定义的常量来设置优先级:MAX_PRIORITY(10)、NORM_PRIORITY(5)、MIN_PRIORITY(1)。
三、操作线程的方法
操作线程的主要方法在Thread类中,下面介绍一些常用的方法:
1.getName()和setName()取得和设置线程名称
Thread t = Thread.currentThread();//静态方法,返回当前正在运行的线程
String name = t.getName();//取得线程的名称
t.setName("线程2—1");//设置线程的名称
2.isAlive()方法——判断线程是否启动
ThreadDemo t = new ThreadDemo();
Boolean b = t.isAlive();//true或false
3.setDaemon()方法——转变为守护线程
ThreadDemo t = new ThreadDemo();
t.setDaemon(true);//设置守护线程,必须在start()方法前面
t.start();
当进程中只剩下守护线程的时候,进程才会结束。
4.join()方法——线程联合
try {
t.join();
}
catch (InterruptedException e)
{ e.printStackTrace();
}
a线程正在运行——b.join();——a线程挂起,b线程强制运行——b线程运行结束——a线程继续运行。
5.interrupt()方法——线程中断
isInterrupt()方法——判断线程是否处于中断状态
t.interrupt();
Boolean b = t.isInterrupted();
当一个线程运行时,另一个线程可以调用另外一个线程对应的interrupt()方法来中断它。
***注意:调用interrupt()方法并不会使正在执行的线程停止执行,它只对调用wait、join、sleep等方法或由于I/O操作等原因受阻的线程产生影响,使其退出暂停执行的状态。
即:interrupt()对正在运行的线程是不起作用的,只有对阻塞的线程有效。