首页 > 代码库 > (十八)多线程
(十八)多线程
多线程
多线程与多进程的区别在于每个进程拥有自己的一整套变量,线程则共享数据。与进程相比,线程更加“轻量级”,创建和撤销一个线程比启动新进程开销要小得多。
实现多线程有两种方法:
- 实现Runnable接口
- 继承Thread类
以下采用两种方法分别实现多线程
实现Runnable接口
public class Football implements Runnable{ private String player; private static int steps=10; public Football(String name){ player = name; } @Override public void run() { while(true){ System.out.println(Thread.currentThread().getId()+":"+player+" is playing football"); try { Thread.currentThread(); Thread.sleep(1200); } catch (InterruptedException e) { e.printStackTrace(); } } }}public class Basketball implements Runnable { private String player; private static int steps=20; public Basketball(String name){ player = name; } @Override public void run() { while(true){ System.out.println(Thread.currentThread().getId()+":"+player+" is playing basketball"); try { Thread.currentThread(); Thread.sleep(700); } catch (InterruptedException e) { e.printStackTrace(); } } }}public class Play { public static void main(String[] args) { // TODO Auto-generated method stub Runnable foot = new Football("Tom"); Runnable basket = new Basketball("John"); Thread t1 = new Thread(foot); Thread t2 = new Thread(basket); t1.start(); t2.start(); }}输出:8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball
继承Thread类
public class Football extends Thread{ private String player; public Football(String name){ player = name; } public void run(){ while(true){ System.out.println(Thread.currentThread().getId()+":"+player+" is playing football"); try { Thread.currentThread(); Thread.sleep(1200); } catch (InterruptedException e) { e.printStackTrace(); } } }}public class Basketball extends Thread{ private String player; public Basketball(String name){ player = name; } public void run(){ while(true){ System.out.println(Thread.currentThread().getId()+":"+player+" is playing basketball"); try { Thread.currentThread(); Thread.sleep(700); } catch (InterruptedException e) { e.printStackTrace(); } } }}public class Play { public static void main(String[] args) { // TODO Auto-generated method stub Thread t1 = new Football("Tom"); Thread t2 = new Basketball("John"); t1.start(); t2.start(); }}输出:8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball8:Tom is playing football
中断线程
当线程的run方法执行到结尾,或者出现未捕获的异常便会停止线程。
可以通过Thread.currentThread().interrupt()来强制终止当前线程。当对一个线程调用该方法时,线程的中断状态会被置位。我们便可以通过Thread.currentThread().isInterrupted()检查这个标志判断线程是否被中断。
但是,如果线程被阻塞(调用sleep或wait),就无法检测中断状态。当一个被阻塞的方法调用interrupt方法时,会被InterruptedException异常中断。
当中断状态被被置位时,调用sleep方法,他不会休眠,而是清除这一状态并抛出InterruptedException异常。
//更改Football部分代码public class Football implements Runnable{ private String player; private static int steps=10; public Football(String name){ player = name; } @Override public void run() { while(!Thread.currentThread().isInterrupted()){ steps--; System.out.println(Thread.currentThread().getId()+":"+player+" is playing football"); try { Thread.currentThread(); Thread.sleep(800); } catch (InterruptedException e) {e.printStackTrace();} if(steps<=0){ Thread.currentThread().interrupt();//设置中断标志 try { Thread.sleep(800);//前面设置了中断标志,因此此处调用会发生InterruptedException异常 } catch (InterruptedException e) { //发生InterruptedException异常后,中断标志会被清除 System.out.println("vvvvvvvvvvvvvvvvvvvvvvvv"); System.out.println("线程:"+Thread.currentThread().getId()+" 调用sleep方法发生异常!"); try { Thread.sleep(800); //因为中断标志被清除了,因此这里调用没问题 System.out.println("线程:"+Thread.currentThread().getId()+" 调用sleep方法成功!"); } catch (InterruptedException e1) {} System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^"); } } } System.out.println("Footbal线程被终止!"); }}
输出
9:John is playing basketball9:John is playing basketball8:Tom is playing football9:John is playing basketball8:Tom is playing football9:John is playing basketballvvvvvvvvvvvvvvvvvvvvvvvv线程:8 调用sleep方法发生异常!9:John is playing basketball线程:8 调用sleep方法成功!^^^^^^^^^^^^^^^^^^^^^^^^8:Tom is playing football9:John is playing basketball
线程状态
线程有6种状态
- 新创建
- 可运行
- 被阻塞
- 等待
- 计时等待
- 被终止
五个阶段:创建、就绪、运行、阻塞、终止
新建线程
new Thread(r)新建一个线程,但还没有运行。
可运行线程
调用start()方法,线程处于runnable状态。可能在运行也可能没有运行。取决于系统。
阻塞线程
当一个线程试图获取一个内部的对象锁,而该锁被其他线程所持有,则该线程处于阻塞状态。当其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程变成非阻塞状态。
等待线程
当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。在调用Object.wait方法或Thread.join方法,,或是等待java.util.concurrent库中的Lock或Condition时,就会出现这种情况。
计时等待
有几个方法有一个超时参数,调用它们会导致线程进入计时等待。比如Thread.sleep(),Object.wait,Thread.join,Lock.tryLock,Condition.await。
终止线程
以下两种可能:
因为run方法正常退出而死亡。
因为一个未被捕获的异常而终止了run方法而意外死亡。
可以调用Thread.currentThread().join()或Thread.currentThread().join(long millis)来等待进程的终止。
线程状态图
线程状态转换
线程属性
(十八)多线程