多线程(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()对正在运行的线程是不起作用的,只有对阻塞的线程有效。