博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程补充
阅读量:6308 次
发布时间:2019-06-22

本文共 21791 字,大约阅读时间需要 72 分钟。

1、线程的状态

线程对象在不同的运行时期有不同的状态,状态信息就存在于State枚举类中

Thread.State :

NEW :至今尚未启动的线程

RUNNABLE:正在java虚拟机中执行的线程

BLOCKED:受阻塞于并等待某个监视器锁的线程

WAITING:无限期的等待另一个线程来执行某一个特定操作的线程

TIMED_WAITING:等待另一个线程来执行某一特定操作的线程

TERMINATED:已退出的线程

 

package com.threadTest.thread.add.state.test01;/** * Created by sky on 2017/3/23. */public class Run {    public static void main(String[] args) {        try {            MyThread thread01 = new MyThread();            System.out.println("main 方法中的状态1: " + thread01.getState());            Thread.sleep(1000);            thread01.start();            Thread.sleep(1000);            System.out.println("main 方法中的状态2: " + thread01.getState());            MyThread thread02 = new MyThread();            System.out.println("main 方法中的状态1: " + thread02.getState());            Thread.sleep(1000);            thread02.start();            Thread.sleep(1000);            System.out.println("main 方法中的状态2: " + thread02.getState());        } catch (InterruptedException e) {            e.printStackTrace();        }    }} 输出: 构造方法中的状态1: RUNNABLE 构造方法中的状态2: RUNNABLE main 方法中的状态1: NEW run 构造方法中的状态1: RUNNABLE main 方法中的状态2: TIMED_WAITING 构造方法中的状态1: RUNNABLE 构造方法中的状态2: RUNNABLE main 方法中的状态1: NEW run 构造方法中的状态1: RUNNABLE main 方法中的状态2: TIMED_WAITING
package com.threadTest.thread.add.state.test01;/** * Created by sky on 2017/3/23. */public class Lock {    public static final Byte lock = new Byte("0");}
package com.threadTest.thread.add.state.test01;/** * Created by sky on 2017/3/23. */public class MyThread extends Thread {    public MyThread() {        try {            System.out.println("构造方法中的状态1: " + Thread.currentThread().getState());            Thread.sleep(1000);            System.out.println("构造方法中的状态2: " + Thread.currentThread().getState());        } catch (InterruptedException e) {            e.printStackTrace();        }    }    @Override    public void run() {        try {            System.out.println("run 构造方法中的状态1: " + Thread.currentThread().getState());            Thread.sleep(1000);            try {                synchronized (Lock.lock) {                    Thread.sleep(1000);                    Lock.lock.wait();                }            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("run 构造方法中的状态2: " + Thread.currentThread().getState());        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

2、线程组

线程组作用:可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行组织。

 

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

1级关联:父对象中有子对象,但并不创建子孙对象。为了有效地对这些线程进行组织管理,通常情况下是创建一个线程组,然后将部分线程归属到该组中,对零散的线程进行有限的组织与规划。

package com.threadTest.thread.add.state.group;/** * Created by sky on 2017/3/23. */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)        {            e.printStackTrace();        }    }}
package com.threadTest.thread.add.state.group;/** * Created by sky on 2017/3/23. */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)        {            e.printStackTrace();        }    }}
package com.threadTest.thread.add.state.group;/** * Created by sky on 2017/3/23. */public class Run {    public static void main(String[] args) {        ThreadA threadA = new ThreadA();        ThreadB threadB = new ThreadB();        ThreadGroup group = new ThreadGroup("线程组");        Thread athread = new Thread(group, threadA);        Thread bthread = new Thread(group, threadB);        athread.start();        bthread.start();        System.out.println("interrupt前活动的线程组: " + group.activeCount());        System.out.println("线程组的名称为: " + group.getName());        //线程中断        group.interrupt();        System.out.println("interrupt后活动的线程组: " + group.activeCount());        group.list();    }}输出:interrupt前活动的线程组: 2线程组的名称为: 线程组interrupt后活动的线程组: 2java.lang.ThreadGroup[name=线程组,maxpri=10]    Thread[Thread-2,5,线程组]    Thread[Thread-3,5,线程组]

2)线程对象关联线程组:多级关联

多级关联:父对象中有子对象,子对象中再创建子对象

package com.threadTest.thread.add.state.group.test02;/** * Created by sky on 2017/3/23. */public class Run {    public static void main(String[] args) {        //在main组中添加一个线程组A,然后在这个A中添加线程对象Z        //方法acctiveGroupCount()个acctiveCount()的值不是固定的        //是系统环境的一个快照        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();        ThreadGroup group = new ThreadGroup(mainGroup, "A");        Runnable runnable = new Runnable() {            @Override            public void run() {                System.out.println("runMethod!");                try {                    Thread.sleep(10000); //线程必须在运行状态下才可以受组管理                } catch (InterruptedException e) {                    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]线程组中的每个活动线程复制到指定的数组中listThread        listGroup[0].enumerate(listThread);        System.out.println(listThread[0].getName());    }}

3)线程组自动归属特性

自动归属:自动归到当前线程组中

package com.threadTest.thread.add.state.group.test03;/** * Created by sky on 2017/3/23. */public class Run {    public static void main(String[] args) {        //方法activeGroupCount()取得当前线程组对象中的子线程数量        //方法acctiveGroupCount()的作用是将线程中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中        System.out.println("A处线程:" + Thread.currentThread().getName()                + "所属的线程组名为:"                + Thread.currentThread().getThreadGroup().getName() + " "                + "中有线程组数量: "                + Thread.currentThread().getThreadGroup().activeGroupCount());        ThreadGroup group = new ThreadGroup("新的组");//自动加到main组中        System.out.println("B处线程:" + Thread.currentThread().getName()                + " 所属的线程组名为: "                + Thread.currentThread().getThreadGroup().getName()                + " 中有线程组数量"                + Thread.currentThread().getThreadGroup().activeGroupCount());        ThreadGroup[] threadGroups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];        Thread.currentThread().getThreadGroup().enumerate(threadGroups);        for (int i = 0; i < threadGroups.length; i++) {            System.out.println("第一个线程组名称为: " + threadGroups[i].getName());        }    }} 输出: A处线程:main所属的线程组名为:main 中有线程组数量: 0 B处线程:main 所属的线程组名为: main 中有线程组数量1 第一个线程组名称为: 新的组

 4)获取根线程组

package com.threadTest.thread.add.state.group.test04;/** * Created by sky on 2017/3/23. */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());    }} 输出: Exception in thread "main" java.lang.NullPointerException     at com.threadTest.thread.add.state.group.test04.Run.main(Run.java:16)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 线程:main 所在的线程组名为: main     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) main线程所在的线程组的父线程组名称是:system     at java.lang.reflect.Method.invoke(Method.java:498)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

5)线程组里加线程组

package com.threadTest.thread.add.state.group.test05;/** * Created by sky on 2017/3/23. */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());        new ThreadGroup(Thread.currentThread().getThreadGroup(), "newGroup");        System.out.println("线程组中线程组数量-加之后:"                + Thread.currentThread().getThreadGroup().activeGroupCount());        System.out.println("父线程组名称:"                + Thread.currentThread().getThreadGroup().getParent().getName());    }} 输出: 线程组名称:main 线程组中活动的线程数量:2 线程组中线程组的数量-加之前:0 线程组中线程组数量-加之后:1 父线程组名称:system

6)组内的线程的批量停止

package com.threadTest.thread.add.state.group.test06;/** * Created by sky on 2017/3/23. */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()        +"结束了:)");    }}
package com.threadTest.thread.add.state.group.test06;/** * Created by sky on 2017/3/23. */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=线程2准备开始死循环了:)ThreadName=线程3准备开始死循环了:)ThreadName=线程4准备开始死循环了:)ThreadName=线程5准备开始死循环了:)调用了interrupt()方法ThreadName=线程1结束了:)ThreadName=线程5结束了:)ThreadName=线程4结束了:)ThreadName=线程3结束了:)ThreadName=线程2结束了:)

7)递归与非递归取得组内对象

package com.threadTest.thread.add.state.group.test07;import com.threadTest.thread.add.state.group.test06.MyThread;/** * Created by sky on 2017/3/23. */public class Run {    public static void main(String[] args) {        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();        ThreadGroup groupA = new ThreadGroup(mainGroup, "A");        Runnable runnable = new Runnable() {            @Override            public void run() {                try {                    System.out.println("runMethod!");                    Thread.sleep(10000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        };        ThreadGroup groupB = new ThreadGroup(groupA, "B");        //分配空间,但不一定全部用完        ThreadGroup[] listGroup1 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];        //传入true是递归取得子组及子孙组        Thread.currentThread().getThreadGroup().enumerate(listGroup1,true);        for (int i = 0; i < listGroup1.length; i++) {            if (null != listGroup1[i]) {                System.out.println(listGroup1[i].getName());            }        }        ThreadGroup[] listGroup2 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];        //传入true是递归取得子组及子孙组        Thread.currentThread().getThreadGroup().enumerate(listGroup2,false);        for (int i = 0; i < listGroup2.length; i++) {            if (null != listGroup2[i]) {                System.out.println(listGroup2[i].getName());            }        }    }} 输出: A B A

 3、使线程具有有序性

package com.threadTest.thread.add.state.order;/** * Created by sky on 2017/3/24. */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 (showNumPosition == addNumber % 3) {                        System.out.println("ThreadName="                                + Thread.currentThread().getName()                                + " runCount=" + addNumber + " " + showChar);                        lock.notifyAll();                        addNumber++;                        printCount++;                        if (3 == printCount) {                            break;                        }                    } else {                        lock.wait();                    }                }            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }} 输出: 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非线程安全

1)出现异常

package com.threadTest.thread.add.state.simpleDateFormat.test01;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by sky on 2017/3/24. */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();        }    }}
package com.threadTest.thread.add.state.simpleDateFormat.test01;import java.text.SimpleDateFormat;/** * Created by sky on 2017/3/24. */public class Test {    public static void main(String[] args) {        //共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04"};        MyThread[] threadArray = new MyThread[4];        for (int i = 0; i < dateStringArray.length; i++) {            threadArray[i] = new MyThread(sdf, dateStringArray[i]);        }        for (int i = 0; i < dateStringArray.length; i++) {            threadArray[i].start();        }    }}输出:Exception in thread "Thread-1" java.lang.NumberFormatException: For input string: ""ThreadName= Thread-0报错了 日期字符串: 2000-01-01 转换成的日期为: 2001-01-01    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)ThreadName= Thread-3报错了 日期字符串: 2004-04-04 转换成的日期为: 2003-03-03

2)解决方法一

package com.threadTest.thread.add.state.simpleDateFormat.test02;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by sky on 2017/3/24. * 实际创建了多个SimpleDateFormat */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();    }}
package com.threadTest.thread.add.state.simpleDateFormat.test02;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by sky on 2017/3/24. */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);            if (!newDateString.equals(dateString)) {                System.out.println("ThreadName= " + this.getName()                + "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);            }        } catch (ParseException e) {            e.printStackTrace();        }    }}
package com.threadTest.thread.add.state.simpleDateFormat.test02;import java.text.SimpleDateFormat;/** * Created by sky on 2017/3/24. */public class Test {    public static void main(String[] args) {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04"};        MyThread[] threadArray = new MyThread[4];        for (int i = 0; i < dateStringArray.length; i++) {            threadArray[i] = new MyThread(sdf, dateStringArray[i]);        }        for (int i = 0; i < dateStringArray.length; i++) {            threadArray[i].start();        }    }}

3)解决方法二

package com.threadTest.thread.add.state.simpleDateFormat.test03;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by sky on 2017/3/24. */public class DateTools {    public static ThreadLocal
t1 = new ThreadLocal
(); public static SimpleDateFormat getSimpleDateFormat(String datePattern) { SimpleDateFormat sdf = null; sdf = t1.get(); if (null == sdf) { sdf = new SimpleDateFormat(datePattern); t1.set(sdf); } return sdf; }}
package com.threadTest.thread.add.state.simpleDateFormat.test03;import com.threadTest.thread.add.state.simpleDateFormat.test02.*;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by sky on 2017/3/24. */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();        }    }}

5、线程中出现异常的处理

package com.threadTest.thread.add.state.exception;/** * Created by sky on 2017/3/24. */public class MyThread extends Thread{    @Override    public void run() {        String username = null;        //NullPointerException        System.out.println(username.hashCode());    }}
package com.threadTest.thread.add.state.exception;/** * Created by sky on 2017/3/24. */public class Main01 {    public static void main(String[] args) {        MyThread myThread1 = new MyThread();        myThread1.setName("线程t1");        //setUncaughtExceptionHandler 对指定的线程对象设置默认的异常处理器        myThread1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {            @Override            public void uncaughtException(Thread t, Throwable e) {                System.out.println("线程: " + t.getName() + " 出现异常: ");                e.printStackTrace();            }        });        myThread1.start();        MyThread myThread2 = new MyThread();        myThread2.setName("线程t2");        myThread2.start();    }}输出:线程: 线程t1 出现异常: Exception in thread "线程t2" java.lang.NullPointerException    at com.threadTest.thread.add.state.exception.MyThread.run(MyThread.java:11)java.lang.NullPointerException    at com.threadTest.thread.add.state.exception.MyThread.run(MyThread.java:11)
package com.threadTest.thread.add.state.exception;/** * Created by sky on 2017/3/24. */public class Main02 {    public static void main(String[] args) {        //setDefaultUncaughtExceptionHandler 为指定线程类的所有线程对象设置默认的异常处理器        MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {            @Override            public void uncaughtException(Thread t, Throwable e) {                System.out.println("线程: " + t.getName() + " 出现异常: ");                e.printStackTrace();            }        });        MyThread myThread1 = new MyThread();        myThread1.setName("线程t1");        myThread1.start();        MyThread myThread2 = new MyThread();        myThread2.setName("线程t2");        myThread2.start();    }}输出:线程: 线程t1 出现异常: java.lang.NullPointerException    at com.threadTest.thread.add.state.exception.MyThread.run(MyThread.java:11)java.lang.NullPointerException线程: 线程t2 出现异常:     at com.threadTest.thread.add.state.exception.MyThread.run(MyThread.java:11)

 

转载于:https://www.cnblogs.com/beaconSky/p/6606425.html

你可能感兴趣的文章
shell学习之用户管理和文件属性
查看>>
day8--socket网络编程进阶
查看>>
node mysql模块写入中文字符时的乱码问题
查看>>
仍需"敬请期待"的微信沃卡
查看>>
分析Ajax爬取今日头条街拍美图
查看>>
内存分布简视图
查看>>
POJ 2918 求解数独
查看>>
如何学习虚拟现实技术vr? vr初级入门教程开始
查看>>
第4 章序列的应用
查看>>
Mysql explain
查看>>
初识闭包
查看>>
java tcp socket实例
查看>>
011 指针的算术运算
查看>>
hdu1874畅通工程续
查看>>
rails 字符串 转化为 html
查看>>
java-学习8
查看>>
AOP动态代理
查看>>
Oracle序列
查看>>
xcodebuild命令行编译错误问题解决
查看>>
Yii2.0 下的 load() 方法的使用
查看>>