多线程之线程状态
由于项目中运用到了多线程,在这里作些总结
先贴个网址http://www.cnblogs.com/lwbqqyumidi
首先感谢原博主,很多内容参照原博主博客,经过梳理总结如下:
关于线程的生命周期,请看下面这张图
一. 五种状态:
新建状态(New):即线程对象创建后
就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态
2.同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),则进入同步阻塞状态
3.其他阻塞:通过调用线程的sleep(),线程会进入到阻塞状态。当sleep()状态超时,线程重新转入就绪状态
阻塞状态说明先记录在这里,后面会介绍
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
介绍下上面各方法:
sleep():休眠
join():加入,该方法执行的时候,让线程进入阻塞,新加入的线程开始执行,并且执行完毕后,原线程才会重新进入就绪状态,然后开始抢cpu资源...
yield():让步,该方法意义不大,后面介绍
synchronized:同步,重点
wait():等待
notify():唤醒
interrupt():打断
上面三个等用到的时候在来介绍,先放着...
二. 线程的创建:
下面介绍两种常见的,还是有其它方式的...
1.继承Thread类,重写该类的run()方法
2.实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象
1 public class SellApple extends Thread{ 2 public void run() { 3 for (int i = 0; i < 1000; i++) { 4 System.out.println("正在卖苹果,i:"+i); 5 } 6 } 7 public static void main(String[] args) { 8 new SellApple().start();//启动 9 new SellApple().start(); 10 } 11 }
1 public class MyRunnable2 implements Runnable { 2 @Override 3 public void run() { 4 for (int i = 0; i < 100; i++) { 5 System.out.println("新线程:"+Thread.currentThread().getName() + " " + i); 6 } 7 } 8 public static void main(String[] args) { 9 MyRunnable2 myRunnable2 = new MyRunnable2(); 10 Thread thread1 = new Thread(myRunnable2); 11 Thread thread2 = new Thread(myRunnable2); 12 thread1.start(); 13 thread2.start(); 14 } 15 }
三.补充
1.当一个线程失去cpu资源进入就绪状态后,下一次该线程同时与其它线程抢cpu资源,这里是随机的,会出现该线程又进入运行状态的情况...
终止线程/实际中运用的多
常用方式是置设置一boolean型的变量,当条件满足时,使线程执行体快速执行完毕
1 public class MyRunnable implements Runnable { 2 //设置终止变量 3 private boolean stop; 4 @Override 5 public void run() { 6 //方法里面就是要执行的内容,当抢到cpu资源后开始执行,中间失去cpu资源后则cpu去执行其他线程内容了,然后再抢到的话就接着上次执行的地方执行 7 //注意,不是重新执行run方法,是接着执行 8 System.out.println("开始"); 9 for (int i = 0; i < 100 && !stop; i++) { 10 System.out.println("新线程:"+Thread.currentThread().getName() + " " + i); 11 } 12 System.out.println("结束"); 13 } 14 public void stopThread() { 15 System.out.println("新线程终止变量=true"); 16 this.stop = true; 17 } 18 }
1 public class Test { 2 public static void main(String[] args) { 3 MyRunnable myRunnable = new MyRunnable(); 4 Thread thread = new Thread(myRunnable); 5 6 for (int i = 0; i < 100; i++) { 7 //当前线程肯定是主线程啊,要是别的线程,程序会在别的线程里面执行 8 System.out.println("主线程:"+Thread.currentThread().getName() + " " + i); 9 if (i == 20) { 10 thread.start();//开启新线程 11 } 12 if(i == 50){//新线程终止变量=true 13 myRunnable.stopThread(); 14 } 15 } 16 } 17 }
看完代码就很明白了,就是设置过滤条件让执行体快速执行完,执行完就终止了....
四.线程状态控制
1.join()
让一个线程等待另一个线程完成才继续执行。如A线程执行体中调用B线程的join()方法,则A线程被阻塞,直到B线程执行完,A才能得以继续执行。
代码run一下就明白了
1 public class MyRunnable implements Runnable { 2 @Override 3 public void run() { 4 for (int i = 0; i < 100; i++) { 5 System.out.println("新线程:"+Thread.currentThread().getName() + " " + i); 6 } 7 } 8 }
public class ThreadTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " " + i); if (i == 30) { thread.start(); try { thread.join(); //字面意思:新线程加入 //表示此时main线程进入阻塞状态,新线程需执行完,main线程才能继续执行.. } catch (InterruptedException e) { e.printStackTrace(); } } } } }
2.sleep()
休眠,让当前的正在执行的线程暂停指定的时间,并进入阻塞状态,时间结束后进入就绪状态,因此sleep()方法常用来暂停线程执行
如果希望新线程必然性的立即执行,直接调用原来线程的sleep(1)即可,睡一个毫秒就够了,因为CPU不会空闲,会切换到新建的线程
看代码:
1 public class ThreadTestBak { 2 public static void main(String[] args) { 3 MyRunnable myRunnable = new MyRunnable(); 4 Thread thread = new Thread(myRunnable); 5 for (int i = 0; i < 100; i++) { 6 System.out.println(Thread.currentThread().getName() + " " + i); 7 if (i == 30) { 8 thread.start(); 9 try { 10 //参数:毫秒数 11 Thread.sleep(1);//当前线程休眠1ms,Thread就是指当前线程,在main方法里面就是主线程了 12 //Thread.sleep(10000); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 } 17 } 18 } 19 }
3.设置线程的优先级
每个线程在执行时都具有一定的优先级,优先级高的线程具有较多的执行机会。
设置线程优先级:setPriority(int priorityLevel)。
参数priority Level范围在1-10之间,常用的有如下三个静态常量值:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
默认是5
优先级高的线程具有较多的执行机会,但是并不一定优先执行,只是机会多而已
每个线程默认的优先级都与创建它的线程的优先级相同,main线程默认具有普通优先级5
获取线程优先级:getPriority()
1 public class MyRunnable implements Runnable { 2 @Override 3 public void run() { 4 for (int i = 0; i < 100; i++) { 5 System.out.println(Thread.currentThread().getName() + " " + i + 6 "当前线程:"+Thread.currentThread().getPriority()); 7 } 8 } 9 }
1 public class ThreadTest { 2 public static void main(String[] args) { 3 MyRunnable myRunnable = new MyRunnable(); 4 Thread thread = new Thread(myRunnable); 5 for (int i = 0; i < 100; i++) { 6 System.out.println(Thread.currentThread().getName() + " " + i); 7 if (i == 1) { 8 thread.setPriority(Thread.MAX_PRIORITY); 9 thread.start(); 10 } 11 } 12 } 13 }
4.yield()
让步
当某个线程调用yiled()方法从运行状态转换到就绪状态后,CPU从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行
该队列中包含原线程吗?真的不会选择优先级低的执行?这里不好测试,在网上查资料,也有同行说这个方法没用
该方法意义不大