线程的状态

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次以后,线程退出循环。

 

posted @ 2020-11-08 22:10  Peterxiazhen  阅读(117)  评论(0编辑  收藏  举报