【Java多线程编程核心技术】7.拾遗增补-笔记总结

相关链接:
【Java多线程编程核心技术】1.Java多线程技能-笔记总结
【Java多线程编程核心技术】2.对象及变量的并发访问(上)-笔记总结
【Java多线程编程核心技术】2.对象及变量的并发访问(下)-笔记总结
【Java多线程编程核心技术】3.线程间通信 -笔记总结
【Java多线程编程核心技术】4.Lock的使用-笔记总结
【Java多线程编程核心技术】5.定时器Timer-笔记总结
【Java多线程编程核心技术】6.单例模式与多线程-笔记总结
【Java多线程编程核心技术】7.拾遗增补-笔记总结
线程的状态
线程对象在不同的运行时期有不同的状态,状态信息就存在于State枚举类中
【Java多线程编程核心技术】7.拾遗增补-笔记总结_第1张图片
这些状态之间某些是可双向切换的,比如waiting和running状态之间可以循环地进行切换
有些事单向切换的,比如线程销毁后并不能自动进入Running状态
【Java多线程编程核心技术】7.拾遗增补-笔记总结_第2张图片

线程组
可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。
【Java多线程编程核心技术】7.拾遗增补-笔记总结_第3张图片
线程组作用:批量管理线程或线程组对象,有效地对线程或线程组对象进行组织

线程对象管理线程组:1级关联
1级关联:父对象中有子对象,但不创建子孙对象。

package test;
import extthread.ThreadA;
import extthread.ThreadB;
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); //将 aThread线程归属到group线程组中
        Thread bThread = new Thread(group, bRunnable);
        aThread.start();
        bThread.start();
        System.out.println("活动的线程数为:" + group.activeCount());
        System.out.println("线程组的名称为:" + group.getName());
    }
}
    Thread aThread = new Thread(group, aRunnable); //将 aThread线程归属到group线程组中

线程对象管理线程组:多级关联
多级关联:父对象中有子对象,子对象中再创建子对象,也就是出现子孙对象的效果。(代码知识点后面章节会覆盖)

线程组自动归属特性

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
第一个线程组名称为:新的组

activeGroupCount():取得当前线程组对象中的子线程组数量
enumerate():将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中

在实例化一个ThreadGroup线程组x时,如果不指定所属的线程组,则x线程组自动归到当前线程对象所属的线程组中。

获取根线程组

Thread.currentThread().getThreadGroup().getParent()   //输出:system
Thread.currentThread().getThreadGroup().getPatent().getParent().getParent()    //报空指针异常

JVM的根线程组就是system,再取其父线程组则出现空异常

线程组里加线程组

          ThreadGroup newGroup = new ThreadGroup(Thread.currentThread()
                   .getThreadGroup(), "newGroup");

显式的方式在一个线程组(此处为main线程组)中添加一个名称为“newGroup”子线程组

组内的线程批量停止

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()方法");

线程组中所有的线程均处于被调用interrupt()方法的状态中,批量执行。

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

Thread.currentThread().getThreadGroup().enumerate(listGroup1, true); //递归
          Thread.currentThread().getThreadGroup().enumerate(listGroup2, false);//非递归

递归取得组内对象:复制子线程组及其子孙线程组
非递归取得组内对象:只复制子线程组

SimpleDateFormat非线程安全
类SimpleDateFormat主要负责日期的转换与格式化,SimpleDateFormat类在多线程环境中,容易造成数据转换及处理的不准确,因为SimpleDateFormat类并不是线程安全的

解决异常方法:通过ThreadLocal类解决
ThreadLocal类详解:http://blog.csdn.net/yangdongchuan1995/article/details/78578337

package extthread;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import tools.DateTools;
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();
        }
    }
}
package tools;
import java.text.SimpleDateFormat;
public class DateTools {
     private static ThreadLocal tl = new ThreadLocal();
     public static SimpleDateFormat getSimpleDateFormat(String datePattern) {
          SimpleDateFormat sdf = null;
          sdf = tl.get();
          if (sdf == null) {
              sdf = new SimpleDateFormat(datePattern);
              tl.set(sdf);
          }
          return sdf;
     }

}
package test.run;
import java.text.SimpleDateFormat;
import extthread.MyThread;
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();
        }
    }
}
输出结果:(什么都不输出,因为没报错)

线程中出现异常的处理

package controller;
import java.lang.Thread.UncaughtExceptionHandler;
import extthread.MyThread;
public class Main2 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.setName("线程t1");
        t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("线程:" + t.getName() + " 出现了异常:");
                e.printStackTrace();
            }
        });

//        MyThread
//        .setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
//            @Override
//            public void uncaughtException(Thread t, Throwable e) {
//                System.out.println("线程:" + t.getName() + " 出现了异常:");
//                e.printStackTrace();
//
//            }
//        });
        t1.start();
        MyThread t2 = new MyThread();
        t2.setName("线程t2");
        t2.start();
    }
}

setUncaughtExceptionHandler():对指定的线程对象设置默认的异常处理器
setDefaultUncaughtExceptionHandler():为指定线程类的所有线程对象设置默认的异常处理器

线程组内处理异常

package extthread;
public class MyThread extends Thread {
     private String num;
     public MyThread(ThreadGroup group, String name, String num) {
          super(group, name);
          this.num = num;
     }
     @Override
     public void run() {
          int numInt = Integer.parseInt(num);
          while (this.isInterrupted() == false) {
              System.out.println("死循环中:" + Thread.currentThread().getName());
          }
     }
}
package extthreadgroup;
public class MyThreadGroup extends ThreadGroup {
     public MyThreadGroup(String name) {
          super(name);
     }
     @Override
     public void uncaughtException(Thread t, Throwable e) {
          super.uncaughtException(t, e);
          this.interrupt();
     }

}
package test.run;
import extthread.MyThread;
import extthreadgroup.MyThreadGroup;
public class Run {
    public static void main(String[] args) {
        MyThreadGroup group = new MyThreadGroup("我的线程组");
        MyThread[] myThread = new MyThread[3];
        for (int i = 0; i < myThread.length; i++) {
            myThread[i] = new MyThread(group, "线程" + (i + 1), "1");
            myThread[i].start();
        }
        MyThread newT = new MyThread(group, "报错线程", "a");
        newT.start();
    }
}

输出结果:
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程2
死循环中:线程3
死循环中:线程3
死循环中:线程3
死循环中:线程3
java.lang.NumberFormatException: For input string: "a"
     at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
     at java.lang.Integer.parseInt(Integer.java:492)
     at java.lang.Integer.parseInt(Integer.java:527)
     at extthread.MyThread.run(MyThread.java:14)

重现uncaughtException方法处理组内线程中断行为时,每个线程对象中的run()方法内部不要有异常catch语句

线程异常处理的传递

     public static void main(String[] args) {
          MyThread myThread = new MyThread();
          // 对象
           myThread
           .setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
          // 类
          MyThread
                   .setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
          myThread.start();
     }

在未设置线程组时,setUncaughtExceptionHandler()先捕获异常,在前者未配置的情况下,才让setDefaultUncaughtExceptionHandler()进行捕获异常。

package extthread;
public class MyThread extends Thread {
     private String num = "a";
     public MyThread() {
          super();
     }
     public MyThread(ThreadGroup group, String name) {
          super(group, name);
     }
     @Override
     public void run() {
          int numInt = Integer.parseInt(num);
          System.out.println("在线程中打印:" + (numInt + 1));
     }
}
package extthreadgroup;
public class MyThreadGroup extends ThreadGroup {
     public MyThreadGroup(String name) {
          super(name);
     }
     @Override
     public void uncaughtException(Thread t, Throwable e) {
//        super.uncaughtException(t, e);
          System.out.println("线程组的异常处理");
          e.printStackTrace();
     }

}
package test.extUncaughtExceptionHandler;
import java.lang.Thread.UncaughtExceptionHandler;
public class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler {
     @Override
     public void uncaughtException(Thread t, Throwable e) {
          System.out.println("对象的异常处理");
          e.printStackTrace();
     }

}
package test.extUncaughtExceptionHandler;
import java.lang.Thread.UncaughtExceptionHandler;
public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {
     @Override
     public void uncaughtException(Thread t, Throwable e) {
          System.out.println("静态的异常处理");
          e.printStackTrace();
     }

}

     public static void main(String[] args) {
          MyThreadGroup group = new MyThreadGroup("我的线程组");
          MyThread myThread = new MyThread(group, "我的线程");
          // 对象
           myThread
           .setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
          // 类
           MyThread
           .setDefaultUncaughtExceptionHandler(new
           StateUncaughtExceptionHandler());
          myThread.start();
     }

在设置了线程组以后,也同样是setUncaughtExceptionHandler()先捕获异常,
再者是线程组的异常处理
将//super.uncaughtException(t, e); 注释取消后, 线程组的异常处理与静态的异常处理 能一起输出。

你可能感兴趣的:(Java多线程,Java多线程编程核心技术)