1 线程的创建
方法1:实现Runnable接口(推荐)
class Runner1 implements Runnable { public void run() { for(int i=0; i<30; i++) System.out.println("No. " + i); } } public class TestThread1 { public static void main(String args[]) { Thread t1 = new Thread(new Runner1()); t1.start(); } }
Runable是任务的概念,如果我们直接这样写,会怎么样呢?只会在原来的线程(Main的)里执行run方法。可见Runable更灵活,任务不用写死在线程里,可以放到不同的线程,甚至线程池里运行。把任务和运行分离。
public class TestThread1 { public static void main(String args[]) { Runnable r1 = new Runner1(); r1.run(); } }
方法2:继承Thread
class Thread1 extends Thread { public void run() { for(int i=0; i<100; i++) { System.out.println("Runner1 :" + i); } } } public class TestThread1 { public static void main(String args[]) { Thread1 t1 = new Thread1(); t1.start(); } }
2 线程的终止
参考:http://www.cnblogs.com/skywang12345/p/3479949.html
http://hapinwater.iteye.com/blog/310558
线程的终止主要有三种方式:
a. interrupt;
b. 通过额外标识位;
c. suspend(暂停),resume(恢复),stop(终止),这三个方法已经过时。suspend和resume就像唱片机,能停能恢复,现在主要被wait/notify取代。stop终止线程太暴力,没时间让线程释放资源,所以被淘汰了。
这些终止是让别的线程终止自己,因别人启动,因别人终止啊~。要终止自己只要从run方法return就行。
2.1 interrupt
每个线程上都有一个标识位interrupted,说明该线程是否被中断。当interrupt()时,只会改标志位,不会真的终止线程。我这里加了一个on标识来关掉这个线程,否则我们就没办法关闭它了。
class ATask extends Thread { private volatile boolean on=true; public void run() { while (on) { System.out.println("I am running!"); for (int i = 0; i < 10000000; i++); } } public void shutdown(){ on=false; } } public class TestThread { public static void main(String[] args) throws Exception{ ATask t = new ATask(); t.start(); //运行一断时间中断线程 Thread.sleep(20); System.out.println("****************************"); System.out.println("Interrupted Thread!"); System.out.println("****************************"); t.interrupt(); Thread.sleep(20); System.out.println("ShutDown Thread!"); System.out.println("****************************"); t.shutdown(); } }
运行结果:
I am running! I am running! **************************** Interrupted Thread! **************************** I am running! I am running! ShutDown Thread! ****************************
interrupted可以通过myThread.isInterrupted()查询,也可以通过Thread.interrupted()重置interrupted标志位(设为fasle)。
java给了线程编写者自由,让他定义在别人中断自己时怎么响应。主要分两种情况,一种是阻塞式的,另一种是非阻塞式。
a. 阻塞式的:调用了sleep(), wait(), join()等方法就会进入阻塞状态。就是说干什么已经不由线程编写者决定,控制权交到sleep里。这些阻塞方法都会抛InterruptedException异常,我么只要在catch里响应Interrupt。可以向下面乖乖地return,就终止了线程(并释放相应资源);也可以直接不管(catch里什么都不写),这样线程就会继续while下去。这里有个小细节,在抛InterruptedException时,虚拟机会重置interrupted标志位。
class ATask extends Thread { public void run() { while(true){ try { System.out.println("I am running!"); sleep(1000); } catch (InterruptedException e) { System.out.println("ATask.run() interrupted!"); return; } } } } public class TestThread { public static void main(String[] args) throws Exception{ //将任务交给一个线程执行 Thread t = new ATask(); t.start(); //运行一断时间中断线程 Thread.sleep(20); System.out.println("****************************"); System.out.println("Interrupted Thread!"); System.out.println("****************************"); t.interrupt(); } }
运行结果:
I am running! **************************** Interrupted Thread! **************************** ATask.run() interrupted!
b. 非阻塞式方法:不是阻塞式的,控制权在自己手里。
class ATask extends Thread { public void run() { //检查程序是否发生中断 while (!Thread.interrupted()) { System.out.println("I am running!"); for (int i = 0; i < 1000000; i++); } System.out.println("ATask.run() interrupted!"); } } public class TestThread{ public static void main(String[] args) throws Exception{ //将任务交给一个线程执行 Thread t = new ATask(); t.start(); //运行一断时间中断线程 Thread.sleep(20); System.out.println("****************************"); System.out.println("Interrupted Thread!"); System.out.println("****************************"); t.interrupt(); } }
运行结果:
I am running! I am running! **************************** Interrupted Thread! **************************** ATask.run() interrupted!
2.2 通过额外标识位
class ATask extends Thread { private volatile boolean on = true; public void run() { while(on){ System.out.println("I am running!"); for (int i = 0; i < 10000000; i++); } } public void shutDown() { on = false; } } public class TestThread { public static void main(String[] args) throws InterruptedException{ //将任务交给一个线程执行 ATask t = new ATask(); t.start(); //运行一断时间中断线程 Thread.sleep(20); System.out.println("****************************"); System.out.println("shutDown Thread!"); System.out.println("****************************"); t.shutDown(); } }
对比2.1,2.2两种方法:
a 都能 自由地处理其他线程的终止请求;
b 都能 在终止时释放资源;
c 2.2不能终止处于阻塞状态的线程。
3 线程的生命周期
线程的状态起始很简单,就是启动->运行->终止。等待,超时等待,阻塞都是一种阻塞状态,到用到时在分析,和线程的状态没太多关系,就那么简单。