线程的状态
1、线程对象在不同的运行时期有不同的状态,状态信息就存在于State枚举类中。
- NEW状态是线程实例化后还从未执行start()方法时的状态;
- RUNNABLE状态是线程进入运行的状态;
- TERMINATED是线程被销毁时的状态;
- TIMED_WAITING状态代表线程执行了Thread.sleep()方法;
- BLOCKED状态出现在某一个线程在等待锁的时候;
- WAITING是线程执行了Object.wait()方法后所处的状态;
package JavaSingleton; public class t3 { public static void main(String[] args) throws InterruptedException { myThread t = new myThread(); System.out.println("进程t现在的状态为:" + t.getState()); Thread.sleep(1000); t.start(); Thread.sleep(1000); System.out.println("进程t现在的状态为: " + t.getState()); } } class myThread extends Thread{ public myThread() { System.out.println("当前的进程是: " + Thread.currentThread().getName() + ", 其状态为:" + Thread.currentThread().getState()); } @Override public void run() { super.run(); System.out.println("当前的进程是: " + Thread.currentThread().getName() + ", 其状态为: " + Thread.currentThread().getState()); } }
当前的进程是: main, 其状态为:RUNNABLE 进程t现在的状态为:NEW 当前的进程是: Thread-0, 其状态为: RUNNABLE 进程t现在的状态为: TERMINATED
TIMED_WAITING
package JavaSingleton; public class t3 { public static void main(String[] args) throws InterruptedException { myThread t = new myThread(); t.start(); Thread.sleep(1000); System.out.println("main方法中的状态: " + t.getState()); } } class myThread extends Thread { @Override public void run() { try { System.out.println("begin sleep"); Thread.sleep(10000); System.out.println(" end sleep"); } catch (InterruptedException e) { e.printStackTrace(); } } }
begin sleep main方法中的状态: TIMED_WAITING end sleep
BLOCKED
package JavaSingleton; public class t3 { public static void main(String[] args) throws InterruptedException { thread1 t = new thread1(); t.setName("t"); t.start(); thread1 t1 = new thread1(); t1.setName("t1"); t1.start(); Thread.sleep(1000); System.out.println("main方法中t1的状态:" + t1.getState()); } } class MyService { synchronized static public void serviceMethod() { try { System.out.println(Thread.currentThread().getName() + "进入了业务方法!"); Thread.sleep(10000); }catch (InterruptedException e) { e.printStackTrace(); // TODO: handle exception } } } class thread1 extends Thread{ @Override public void run() { super.run(); MyService.serviceMethod(); } } class thread2 extends Thread{ @Override public void run() { super.run(); MyService.serviceMethod(); } }
t进入了业务方法! main方法中t1的状态:BLOCKED t1进入了业务方法!
WAITING
package JavaSingleton; public class t3 { public static void main(String[] args) throws InterruptedException { mythread t = new mythread(); t.start(); Thread.sleep(1000); System.out.println("main方法中t的状态:" + t.getState()); } } class Lock { public static final Byte lock = new Byte("0"); } class mythread extends Thread{ @Override public void run() { try { synchronized (Lock.lock) { Lock.lock.wait(); } }catch (InterruptedException e) { e.printStackTrace(); } } }
main方法中t的状态:WAITING
线程组:
线程对象关联线程组:1级关联
1级关联就是父对象中有子对象,但并不创建子孙对象。那么为什么要创建线程组?对于一些线程,为了有效地对这些线程进行组织管理,通常情况下是创建一个线程组,然后再将部分线程归属到该组中。这样能对零散的线程对象进行有效地组织和规划。
package JavaSingleton; public class t3 { public static void main(String[] args) throws InterruptedException { thread1 t1 = new thread1(); thread2 t2 = new thread2(); ThreadGroup group = new ThreadGroup("xzb的线程组"); Thread aThread = new Thread(group, t1); //将某个线程添加给某个线程组 Thread bThread = new Thread(group, t2); aThread.start(); bThread.start(); System.out.println("活动的线程数为:" + group.activeCount()); System.out.println("线程组的名称为:" + group.getName()); } } class thread1 extends Thread{ @Override public void run() { try { while (!Thread.currentThread().isInterrupted()) { System.out.println("ThreadName=" + Thread.currentThread().getName()); Thread.sleep(3000); } } catch (InterruptedException e) { e.printStackTrace(); } } } class thread2 extends Thread{ @Override public void run() { try { while (!Thread.currentThread().isInterrupted()) { System.out.println("ThreadName=" + Thread.currentThread().getName()); Thread.sleep(3000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
ThreadName=Thread-2 活动的线程数为:2 ThreadName=Thread-3 线程组的名称为:xzb的线程组
线程组自动归属特性
自动归属就是自动归到当前线程组中。在实例化一个ThreadGroup线程组x时,如果不指定所属的线程组,则x线程组自动归到当前线程对象所属的线程组中。
package JavaSingleton; /* 方法activeGroupCount() 取得当前线程组对象中的子线程组的数量 * 方法enumerate的作用是将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中 */ public class t3 { public static void main(String[] args) throws InterruptedException { System.out.println("A处线程:" + Thread.currentThread().getName() + ", 所属线程:" + Thread.currentThread().getThreadGroup().getName() + ", 组中有线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount()); ThreadGroup group = new ThreadGroup("第一个线程组"); ThreadGroup group1 = new ThreadGroup("第二个线程组"); System.out.println("B处线程:" + Thread.currentThread().getName() + ", 所属线程:" + Thread.currentThread().getThreadGroup().getName() + ", 组中有线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount()); ThreadGroup[] tg = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()]; Thread.currentThread().getThreadGroup().enumerate(tg); for (int i = 0; i < tg.length; i++) System.out.println("第一个线程组名称为:" + tg[i].getName()); } } class thread1 extends Thread{ } class thread2 extends Thread{ }
A处线程:main, 所属线程:main, 组中有线程组数量:0 B处线程:main, 所属线程:main, 组中有线程组数量:2 第一个线程组名称为:第一个线程组 第一个线程组名称为:第二个线程组
package JavaSingleton; /* 方法activeGroupCount() 取得当前线程组对象中的子线程组的数量 * 方法enumerate的作用是将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中 */ public class t3 { public static void main(String[] args) throws InterruptedException { System.out.println("线程:" + Thread.currentThread().getName() + ", 所属线程:" + Thread.currentThread().getThreadGroup().getName()); System.out.println("main线程所在线程组的父线程组为:" + Thread.currentThread().getThreadGroup().getParent().getName()); Thread.sleep(1000); System.out.println("main线程所在线程组的父线程组的父线程组为:" + Thread.currentThread().getThreadGroup().getParent().getParent().getName()); } }
线程:main, 所属线程:main main线程所在线程组的父线程组为:system Exception in thread "main" java.lang.NullPointerException at JavaSingleton.t3.main(t3.java:12)
从打印结果来看,JVM的根线程组就是system,再求其父线程组则出现异常。
package JavaSingleton; /* 方法activeGroupCount() 取得当前线程组对象中的子线程组的数量 * 方法enumerate的作用是将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中 */ public class t3 { public static void main(String[] args) throws InterruptedException { System.out.println("线程组名称:" + Thread.currentThread().getThreadGroup().getName()); System.out.println("线程组中活动的线程数为:" + Thread.currentThread().getThreadGroup().activeCount()); System.out.println("线程组中线程组的数量为——加之前:" + Thread.currentThread().getThreadGroup().activeGroupCount()); ThreadGroup newGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), "newGroup"); //创建新的线程组加入到当前线程组中 System.out.println("线程组中线程组的数量为——加之后:" + Thread.currentThread().getThreadGroup().activeGroupCount()); System.out.println("父线程组名称:" + Thread.currentThread().getThreadGroup().getParent().getName()); } }
线程组名称:main 线程组中活动的线程数为:1 线程组中线程组的数量为——加之前:0 线程组中线程组的数量为——加之后:1 父线程组名称:system
从代码和打印结果看,本实验用显示的方式在一个线程组中添加了一个子线程组。
线程组内的线程批量停止
package JavaSingleton; /* 方法activeGroupCount() 取得当前线程组对象中的子线程组的数量 * 方法enumerate的作用是将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中 */ public class t3 { public static void main(String[] args) throws InterruptedException { ThreadGroup tg = new ThreadGroup("线程组"); for (int i = 0; i < 5; i++){ mythread1 mt = new mythread1(tg, "线程" + (i + 1)); mt.start(); //线程必须运行才会受到组的管理 } Thread.sleep(5000); tg.interrupt(); System.out.println("调用了interrupt()方法"); } } class mythread1 extends Thread { public mythread1 (ThreadGroup tg, String name) { super(tg, name); } public void run() { System.out.println("ThreadName = " + Thread.currentThread().getName() + "准备开始死循环了"); while (!this.isInterrupted()){} System.out.println("ThreadName = " + Thread.currentThread().getName() + "结束了"); } }
ThreadName = 线程1准备开始死循环了 ThreadName = 线程5准备开始死循环了 ThreadName = 线程4准备开始死循环了 ThreadName = 线程3准备开始死循环了 ThreadName = 线程2准备开始死循环了 调用了interrupt()方法 ThreadName = 线程5结束了 ThreadName = 线程4结束了 ThreadName = 线程1结束了 ThreadName = 线程3结束了 ThreadName = 线程2结束了
通过将线程归属到线程组中,ThreadGroup中的interrupt()方法批量中断了线程组内的线程,这就是ThreadGroup的作用。
递归与非递归取得线程组内的对象
package JavaSingleton; /* 方法activeGroupCount() 此线程组及其子组中的所有活动线程组 */ public class t3 { public static void main(String[] args) throws InterruptedException { ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); ThreadGroup groupA = new ThreadGroup(mainGroup, "groupA"); //当前线程组增加了子线程组A System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); Runnable runnable = new Runnable() { public void run() { try { System.out.println("runMethod!"); Thread.sleep(10000); }catch (InterruptedException e) { e.printStackTrace(); } }; }; ThreadGroup groupB = new ThreadGroup(groupA, "groupB"); System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); //分配空间,但不一定全部用完 ThreadGroup[] listGroup1 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()]; //new ThreadGroup[1] //给listGroup1传入true是递归取得子线程组合及子孙组 Thread.currentThread().getThreadGroup().enumerate(listGroup1, true); System.out.println("当前线程所属线程组的子线程组及子孙组:"); for(int i = 0; i < listGroup1.length; i++) { if(listGroup1[i] != null) { System.out.println(listGroup1[i].getName()); } } ThreadGroup[] listGroup2 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()]; Thread.currentThread().getThreadGroup().enumerate(listGroup2, false);//不复制子线程组 System.out.println("当前线程所属线程组的子线程组:"); for(int i = 0; i < listGroup2.length; i++) { if(listGroup2[i] != null) { System.out.println(listGroup2[i].getName()); } } } }
当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:0 当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:1 当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:2 当前线程所属线程组的子线程组及子孙组: groupA groupB 当前线程所属线程组的子线程组: groupA
ThreadGroup的一些总结:
1、ThreadGroup与Thread的关系
Java中,在默认情况下,新的线程都会加入到main线程所在的group中 ,main线程的group和线程同名。ThreadGroup线程组中还能嵌套ThreadGrou子线程组。
2、创建ThreadGroup
public ThreadGroup(String name) public ThreadGroup(ThreadGroup parent, String name)
第一个构造函数为ThreadGroup赋予名字,该ThreadGroup的父ThreadGroup是创建他的线程所在的ThreadGroup;
第二个构造函数除了能赋予名字外,还能显示地指定父ThreadGroup
3、复制ThreadGroup数组
public int enumerate(ThreadGroup[] list) public int enumerate(ThreadGroup[] list, boolean recurse)
第一种方法会将ThreadGroup中的active线程组全部复制到ThreadGroup[]数组中,其中参数recurse如果为true,则该方法会将子线程组和子孙线程组一起复制到ThreadGroup[] list中;
如果参数为false,则不复制子孙线程组。
4、ThreadGroup的操作
-
-
activeCount() //获取ThreadGroup中活跃的线程数量
-
activeGroupCount() //获取ThreadGroup中活跃的线程组的数量
-
getName() //获取ThreadGroup的名字
-
getParent //获取ThreadGroup的父线程组,若不存在,则返回null
-
5、递归于非递归取得组内的对象
package JavaSingleton; /* 方法activeGroupCount() 此线程组及其子组中的所有活动线程组 */ public class t3 { public static void main(String[] args) throws InterruptedException { ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); ThreadGroup groupA = new ThreadGroup(mainGroup, "groupA"); //当前线程组增加了子线程组A System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); Runnable runnable = new Runnable() { public void run() { try { System.out.println("runMethod!"); Thread.sleep(10000); }catch (InterruptedException e) { e.printStackTrace(); } }; }; ThreadGroup groupB = new ThreadGroup(groupA, "groupB"); System.out.println("当前线程的线程组:" + mainGroup.getName() + " 当前线程组的线程数:" + mainGroup.activeCount() + " 当前线程组的子线程组数:" + mainGroup.activeGroupCount()); //分配空间,但不一定全部用完 ThreadGroup[] listGroup1 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()]; //new ThreadGroup[1] //给listGroup1传入true是递归取得子线程组合及子孙组 Thread.currentThread().getThreadGroup().enumerate(listGroup1, true); System.out.println("当前线程所属线程组的子线程组及子孙组:"); for(int i = 0; i < listGroup1.length; i++) { if(listGroup1[i] != null) { System.out.println(listGroup1[i].getName()); } } ThreadGroup[] listGroup2 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()]; Thread.currentThread().getThreadGroup().enumerate(listGroup2, false);//不复制子孙线程组 System.out.println("当前线程所属线程组的子线程组:"); for(int i = 0; i < listGroup2.length; i++) { if(listGroup2[i] != null) { System.out.println(listGroup2[i].getName()); } } } }
当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:0 当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:1 当前线程的线程组:main 当前线程组的线程数:1 当前线程组的子线程组数:2 当前线程所属线程组的子线程组及子孙组: groupA groupB 当前线程所属线程组的子线程组: groupA
多线程,使得线程具有有序性
package JavaSingleton; import java.util.concurrent.locks.Lock; /* * 使程序具有有序性 */ public class t4 { public static void main(String[] args) { Object lock = new Object(); mythread t1 = new mythread(lock ,"A", 1); mythread t2 = new mythread(lock ,"B", 2); mythread t3 = new mythread(lock ,"C", 0); t1.start(); t2.start(); t3.start(); } } class mythread extends Thread { private Object lock; private String showChar; private int showNumPosition;//展示编号 private int printCount = 0;//统计打印了几个字母,也能控制打印的字母数 volatile private static int addNumber = 1; //构造方法 public mythread(Object lock ,String showChar, int showNumPosition) { this.lock = lock; this.showChar = showChar; this.showNumPosition = showNumPosition; } @Override public void run() { try { synchronized(lock) { while(true) { if(addNumber % 3 == showNumPosition) { System.out.println("ThreadName = " + Thread.currentThread().getName()+ " runCount" + addNumber + " " + showChar); lock.notifyAll(); addNumber++; printCount++; if(printCount == 3) { break; } }else{ lock.wait(); } } } } catch (InterruptedException e) { e.printStackTrace(); } } }
ThreadName = Thread-0 runCount1 A ThreadName = Thread-1 runCount2 B ThreadName = Thread-2 runCount3 C ThreadName = Thread-0 runCount4 A ThreadName = Thread-1 runCount5 B ThreadName = Thread-2 runCount6 C ThreadName = Thread-0 runCount7 A ThreadName = Thread-1 runCount8 B ThreadName = Thread-2 runCount9 C
从打印结果上看,A、B、C这些线程依次有序执行。
线程分析:
1、当三个线程启动后,如果是b和c线程拿到锁,则会进入到else中线程等待(并且释放锁lock),所以第一个运行的是A线程。此时运行代码后输出:ThreadName = Thread-0 runCount1 A。全局addNumber修改为2,A线程中的printCount变成1,当A线程再次执行循环时,进入else代码块,线程等待;
2、此时如果时线程C拿到锁,则线程C会进入else块,线程等待,然后线程B拿到锁,由于当前线程A修改了全局addNumber,所有线程B在进入循环判断时,构造参数showNumPosition正好就是初始的addNumber%3的值此时运行代码后输出:ThreadName = Thread-1 runCount2 B并唤醒其他线程,此时A和C线程被唤醒,争抢锁。全局addNumber修改为3,B线程中的printCount变成1,当C线程再次执行循环时,进入else代码块,线程等待;此时如果是A线程获得锁,则会进入else块,线程等待;
3、然后C线程拿到锁,由于当前线程B修改了全局addNumber,所有线程C在进入循环判断时,构造参数showNumPosition正好就是初始的addNumber%3的值此时运行代码后出:ThreadName = Thread-2 runCount3 C并唤醒其他线程,此时A和B线程被唤醒,争抢锁全局addNumber修改为4,c线程中的printCount变成1,当c线程再次执行循环时,进入else代码块,线程等待;
4、以此类推,当A、B、C所有线程都依次执行3次以后,线程退出循环。
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!