多线程:7.线程状态,线程组以及相关异常

2016-09-05  本文已影响46人  81bad73e9053

1.线程的状态

public enum State {
    /**
     * The thread has been created, but has never been started.
     */
    NEW,
    /**
     * The thread may be run.
     */
    RUNNABLE,
    /**
     * The thread is blocked and waiting for a lock.
     */
    BLOCKED,
    /**
     * The thread is waiting.
     */
    WAITING,
    /**
     * The thread is waiting for a specified amount of time.
     */
    TIMED_WAITING,
    /**
     * The thread has been terminated.
     */
    TERMINATED
}

1.1NEW RUNNABLE TERMINATED

public class MyThread extends Thread {

    public MyThread() {
        //构造方法是被主线程调用的,因此这里的状态是主线程的状态
        System.out.println("构造方法中的状态:" + Thread.currentThread().getState());
    }

    @Override
    public void run() {
        System.out.println("run方法中的状态:" + Thread.currentThread().getState());
    }

}

public class Run {

    // NEW,
    // RUNNABLE,
    // TERMINATED,

    // BLOCKED,
    // WAITING,
    // TIMED_WAITING,

    public static void main(String[] args) {
        try {
            MyThread t = new MyThread();
            System.out.println("main方法中的状态1:" + t.getState());
            Thread.sleep(1000);
            t.start();
            Thread.sleep(1000);
            System.out.println("main方法中的状态2:" + t.getState());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    } 
}
运行结果:
构造方法中的状态:RUNNABLE//构造方法是由主线程调用的,因此这里的状态是主线程的状态
main方法中的状态1:NEW
run方法中的状态:RUNNABLE
main方法中的状态2:TERMINATED

1.2 TIME_WAITING

public 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();
        }
    } 
}

public class Run { 
    public static void main(String[] args) {
        try {
            MyThread t = new MyThread();
            t.start();
            Thread.sleep(1000);
            System.out.println("main方法中的状态:" + t.getState());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}
运行结果:
begin sleep
main方法中的状态:TIMED_WAITING
  end sleep

1.3 BLOCKED出现在某一个线程正在等待锁的时候

1.4 WAITING 线程执行了wait()方法后的状态

public class Lock {

    public static final Byte lock = new Byte("0");

}

public class MyThread extends Thread {

    @Override
    public void run() {
        try {
            synchronized (Lock.lock) {
                Lock.lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class Run { 
     
    public static void main(String[] args) {
        try {
            MyThread t = new MyThread();
            t.start();
            Thread.sleep(1000);
            System.out.println("main方法中的t状态:" + t.getState());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
运行结果:
main方法中的t状态:WAITING

2.线程组

线程组中可以有线程对象也可以有线程组

2.1线程对象关联线程组:1级关联



public class ThreadA extends Thread {

    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                System.out
                        .println("ThreadName=" + 
                                Thread.currentThread().
                                getName());
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 
}


public class ThreadB extends Thread {

    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                System.out
                        .println("ThreadName=" + 
                                Thread.currentThread().
                                getName());
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 
}

public class Run {

    public static void main(String[] args) {
        ThreadA aRunnable = new ThreadA();
        ThreadB bRunnable = new ThreadB();

        ThreadGroup group = new ThreadGroup("高洪岩的线程组");

        Thread aThread = new Thread(group, aRunnable);
        Thread bThread = new Thread(group, bRunnable);
        aThread.start();
        bThread.start();

        System.out.println("活动的线程数为:" + group.activeCount());
        System.out.println("线程组的名称为:" + group.getName());

    }
}
运行结果:
ThreadName=Thread-2
ThreadName=Thread-3
活动的线程数为:2
线程组的名称为:高洪岩的线程组
ThreadName=Thread-2
ThreadName=Thread-3
ThreadName=Thread-2
ThreadName=Thread-3

2.2线程对象关联线程组 :多级关联

public class Run {

    public static void main(String[] args) {

        // 在main组中添加一个线程组A,然后在这个A组中添加线程对象Z
        // 方法activeGroupCount()和activeCount()的值不是固定的
        // 是系统中环境的一个快照
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        ThreadGroup group = new ThreadGroup(mainGroup, "A");
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("runMethod!");
                    Thread.sleep(10000);// 线程必须在运行状态才可以受组管理
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };

        Thread newThread = new Thread(group, runnable);
        newThread.setName("Z");
        newThread.start();// 线程必须启动然后才归到组A中
        // ///
        ThreadGroup[] listGroup = new ThreadGroup[Thread.currentThread()
                .getThreadGroup().activeGroupCount()];
        Thread.currentThread().getThreadGroup().enumerate(listGroup);
        System.out.println("main线程中有多少个子线程组:" + listGroup.length + " 名字为:"
                + listGroup[0].getName());
        Thread[] listThread = new Thread[listGroup[0].activeCount()];
        listGroup[0].enumerate(listThread);
        System.out.println(listThread[0].getName());

    }

}

2.3线程组自动归属特性

自动归属就是自动归到当前线程组中

public class Run {
    public static void main(String[] args) {
        System.out.println("A处线程:"+Thread.currentThread().getName()+" 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());
        ThreadGroup group=new ThreadGroup("新的组");
        System.out.println("A处线程:"+Thread.currentThread().getName()+" 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());
        ThreadGroup[] threadGroup=new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
        Thread.currentThread().getThreadGroup().enumerate(threadGroup);
        for (int i = 0; i < threadGroup.length; i++) {
            System.out.println("第一个线程组名称为:"+threadGroup[i].getName());
        }
    }
}
运行结果;
A处线程:main 中有线程组数量:0
A处线程:main 中有线程组数量:1
第一个线程组名称为:新的组

2.4获取根线程组

public class Run {

    public static void main(String[] args) {
        System.out.println("线程:" + Thread.currentThread().getName()
                + " 所在的线程组名为:"
                + Thread.currentThread().getThreadGroup().getName());
        System.out
                .println("main线程所在的线程组的父线程组的名称是:"
                        + Thread.currentThread().getThreadGroup().getParent()
                                .getName());
        System.out.println("main线程所在的线程组的父线程组的父线程组的名称是:"
                + Thread.currentThread().getThreadGroup().getParent()
                        .getParent().getName());
    }

}
运行结果:jvm的根线程组就是system
线程:main 所在的线程组名为:main
main线程所在的线程组的父线程组的名称是:system
Exception in thread "main" java.lang.NullPointerException
    at test.run.Run.main(Run.java:15)

2.5线程组里添加线程组


public class Run {

    public static void main(String[] args) {

        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

2.6组内的线程批量停止

public class MyThread extends Thread {

    public MyThread(ThreadGroup group, String name) {
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("ThreadName=" + Thread.currentThread().getName()
                + "准备开始死循环了:)");
        while (!this.isInterrupted()) {
        }
        System.out.println("ThreadName=" + Thread.currentThread().getName()
                + "结束了:)");
    }

}
public class Run {

    public static void main(String[] args) {
        try {
            ThreadGroup group = new ThreadGroup("我的线程组");

            for (int i = 0; i < 5; i++) {
                MyThread thread = new MyThread(group, "线程" + (i + 1));
                thread.start();
            }
            Thread.sleep(5000);
            group.interrupt();
            System.out.println("调用了interrupt()方法");
        } catch (InterruptedException e) {
            System.out.println("停了停了!");
            e.printStackTrace();
        } 
    } 
}

运行结果:
ThreadName=线程1准备开始死循环了:)
ThreadName=线程5准备开始死循环了:)
ThreadName=线程4准备开始死循环了:)
ThreadName=线程3准备开始死循环了:)
ThreadName=线程2准备开始死循环了:)
调用了interrupt()方法
ThreadName=线程3结束了:)
ThreadName=线程1结束了:)
ThreadName=线程5结束了:)
ThreadName=线程4结束了:)
ThreadName=线程2结束了:)

3.有序运行


public 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) {
        super();
        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();
        }

    }
}
public class Run {

    public static void main(String[] args) {

        Object lock = new Object();

        MyThread a = new MyThread(lock, "A", 1);
        MyThread b = new MyThread(lock, "B", 2);
        MyThread c = new MyThread(lock, "C", 0);

        a.start();
        b.start();
        c.start(); 
    } 
}


运行结果:
ThreadName=Thread-0 runCount=1 A
ThreadName=Thread-1 runCount=2 B
ThreadName=Thread-2 runCount=3 C
ThreadName=Thread-0 runCount=4 A
ThreadName=Thread-1 runCount=5 B
ThreadName=Thread-2 runCount=6 C
ThreadName=Thread-0 runCount=7 A
ThreadName=Thread-1 runCount=8 B
ThreadName=Thread-2 runCount=9 C

4.SimpleDateFormat非线程安全

4.1错误

public class MyThread extends Thread {

    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = sdf.parse(dateString);
            String newDateString = sdf.format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"
                        + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        } 
    } 
}

public class Test {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String[] dateStringArray = new String[] { "2000-01-01", "2000-01-02",
                "2000-01-03", "2000-01-04", "2000-01-05", "2000-01-06",
                "2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10" };

        MyThread[] threadArray = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }
}
运行结果:
ThreadName=Thread-2报错了 日期字符串:2000-01-03 转换成的日期为:2000-01-02
ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:2000-01-01
ThreadName=Thread-6报错了 日期字符串:2000-01-07 转换成的日期为:1970-01-07

4.1解决方式1

public class MyThread extends Thread {

    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateTools.parse("yyyy-MM-dd", dateString);
            String newDateString = DateTools.format("yyyy-MM-dd", dateRef)
                    .toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"
                        + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

    }

}

public class DateTools {

    public static Date parse(String formatPattern, String dateString)
            throws ParseException {
        return new SimpleDateFormat(formatPattern).parse(dateString);
    }

    public static String format(String formatPattern, Date date) {
        return new SimpleDateFormat(formatPattern).format(date).toString();
    }

}

public class Test {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String[] dateStringArray = new String[] { "2000-01-01", "2000-01-02",
                "2000-01-03", "2000-01-04", "2000-01-05", "2000-01-06",
                "2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10" };

        MyThread[] threadArray = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }
}

4.2解决方式2

public class DateTools {

    private static ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>();

    public static SimpleDateFormat getSimpleDateFormat(String datePattern) {
        SimpleDateFormat sdf = null;
        sdf = tl.get();
        if (sdf == null) {
            sdf = new SimpleDateFormat(datePattern);
            tl.set(sdf);
        }
        return sdf;
    }

}

public class MyThread extends Thread {

    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(
                    dateString);
            String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd")
                    .format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"
                        + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

    }

}


public class Test {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String[] dateStringArray = new String[] { "2000-01-01", "2000-01-02",
                "2000-01-03", "2000-01-04", "2000-01-05", "2000-01-06",
                "2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10" };

        MyThread[] threadArray = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }
}

上一篇 下一篇

猜你喜欢

热点阅读