zoukankan      html  css  js  c++  java
  • Java多线程编程核心技术---拾遗增补

    线程状态验证
    public class MyThread extends Thread {
    	public MyThread() {
    		System.out.println("构造方法中的状态:" + Thread.currentThread().getState());//RUNNABLE
    	}
    	@Override
    	public void run() {
    		System.out.println("run方法中的状态:" + Thread.currentThread().getState());//RUNNABLE
    		try {
    			Thread.sleep(1000);
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyThread thread = new MyThread();
    			System.out.println("main方法中的状态1:" + thread.getState());//NEW
    			Thread.sleep(1000);
    			thread.start();
    			Thread.sleep(500);
    			System.out.println("main方法中的状态2:" + thread.getState());//TIMED_WAITING
    			Thread.sleep(1200);
    			System.out.println("main方法中的状态3:" + thread.getState());//TERMINATED
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    运行程序控制台输出结果如下:

    构造方法中的状态:RUNNABLE
    main方法中的状态1:NEW
    run方法中的状态:RUNNABLE
    main方法中的状态2:TIMED_WAITING
    main方法中的状态3:TERMINATED
    

    public class Service {
    	synchronized static public void serviceMethod(){
    		try {
    			System.out.println(Thread.currentThread().getName() + "进入了serviceMethod方法");
    			Thread.sleep(10000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    public class MyThread1 extends Thread {
    	@Override
    	public void run() {
    		Service.serviceMethod();
    	}
    }
    
    public class MyThread2 extends Thread {
    	@Override
    	public void run() {
    		Service.serviceMethod();
    	}
    }
    
    public class Main {
    	public static void main(String[] args) throws InterruptedException {
    		MyThread1 t1 = new MyThread1();
    		t1.start();
    		MyThread1 t2 = new MyThread1();
    		t2.start();
    		Thread.sleep(2000);
    		System.out.println("main t1 :" + t1.getState());
    		System.out.println("main t2 :" + t2.getState());
    	}
    }
    

    运行程序,控制台打印结果如下:

    Thread-0进入了serviceMethod方法
    main t1 :TIMED_WAITING
    main t2 :BLOCKED
    Thread-1进入了serviceMethod方法
    

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

    所谓的1级关联就是父对象中有子对象,但是并不创建孙对象。

    public class ThreadA extends Thread {
    	@Override
    	public void run() {
    		try {
    			while (!Thread.currentThread().isInterrupted()) {
    				System.out.println("ThreadName=" + ThreadA.currentThread().getName());
    				Thread.sleep(3000);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    public class Main {
    	public static void main(String[] args) {
    		ThreadA a = new ThreadA();
    		ThreadB b = new ThreadB();
    		ThreadGroup group = new ThreadGroup("My-Thread-Group");
    		Thread aThread = new Thread(group, a);
    		Thread bThread = new Thread(group, b);
    		aThread.start();
    		bThread.start();
    		System.out.println("活动的线程数:" + group.activeCount());
    		System.out.println("线程组的名称:" + group.getName());
    	}
    }
    

    运行程序,控制台打印结果如下:

    活动的线程数:2
    ThreadName=Thread-3
    ThreadName=Thread-2
    线程组的名称:My-Thread-Group
    ThreadName=Thread-3
    ThreadName=Thread-2
    ThreadName=Thread-3
    ThreadName=Thread-2
    ......
    
    线程对象关联线程组:多级关联

    所谓的多级关联就是父对象中有子对象,子对象中再创建子对象,也就是出现孙对象的效果。

    public class Main {
    	public static void main(String[] args) {
    		ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
    		ThreadGroup group = new ThreadGroup(mainGroup, "A");
    		Runnable runnable = new Runnable() {
    			
    			@Override
    			public void run() {
    				try {
    					System.out.println("run method");
    					Thread.sleep(10000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		};
    		Thread newThread = new Thread(group, runnable);
    		newThread.setName("Z");
    		newThread.start();
    		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());
    	}
    }
    

    运行程序控制台打印结果如下:

    run method
    main线程中有1个子线程,名字:A
    Z
    

    此种写法在开发中不常见,太复杂不利于管理。


    如果实例化线程组时不指定所属的线程组,则实例化的线程组归到当前线程对象所属的线程组中

    public class Main {
    	public static void main(String[] args) {
    		System.out.println("当前线程名:" + Thread.currentThread().getName());
    		System.out.println("所属线程组:" + Thread.currentThread().getThreadGroup().getName());
    		System.out.println("线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
    		ThreadGroup group = new ThreadGroup("New-group");
    		System.out.println("线程组数量:" + 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("第" + (i + 1) + "个线程组名字为:" + threadGroups[i].getName());
    		}
    		//如果实例化线程组时不指定所属的线程组,则实例化的线程组归到当前线程对象所属的线程组中
    	}
    }
    

    运行以上程序,控制台打印结果如下:

    当前线程名:main
    所属线程组:main
    线程组数量:0
    线程组数量:1
    第1个线程组名字为:New-group
    

    获取根线程组

    //获取根线程组
    public class Main {
    	public static void main(String[] args) {
    		System.out.println("当前线程名:" + Thread.currentThread().getName());
    		System.out.println("所属线程组:" + Thread.currentThread().getThreadGroup().getName());
    		System.out.println("当前线程所属线程组的父线程组名:" + Thread.currentThread().getThreadGroup().getParent().getName());
    		System.out.println("当前线程所属线程组的父线程组的父线程组名:" + Thread.currentThread().getThreadGroup().getParent().getParent().getName());
    	}
    }
    

    控制台输出结果如下:

    当前线程名:main
    所属线程组:main
    当前线程所属线程组的父线程组名:system
    Exception in thread "main" java.lang.NullPointerException
    	at com.umgsai.thread.thread66.Main2.main(Main2.java:9)
    

    运行结果说明JVM的根线程组是system,再取其父线程组则抛出空指针异常。


    线程组里加线程组

    public class Main3 {
    	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 group = 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
    

    组内的线程批量停止

    public class MyThread extends Thread {
    	public MyThread(ThreadGroup group, String name) {
    		super(group, name);
    	}
    	@Override
    	public void run() {
    		System.out.println(Thread.currentThread().getName() + "准备开始死循环了");
    		while (!this.isInterrupted()) {
    		}
    		System.out.println(Thread.currentThread().getName() + "结束死循环了");
    	}
    }
    
    public class Main {
    	public static void main(String[] args) {
    		try {
    			ThreadGroup group = new ThreadGroup("My-group");
    			for (int i = 0; i < 5; i++) {
    				MyThread thread = new MyThread(group, "Thread-" + i);
    				thread.start();
    			}
    			Thread.sleep(5000);
    			group.interrupt();
    			System.out.println("调用了interrupt方法");
    		} catch (Exception e) {
    			System.out.println("停了");
    			e.printStackTrace();
    		}
    	}
    }
    

    控制台输出如下:

    Thread-3准备开始死循环了
    Thread-2准备开始死循环了
    Thread-1准备开始死循环了
    Thread-4准备开始死循环了
    调用了interrupt方法
    Thread-3结束死循环了
    Thread-2结束死循环了
    Thread-4结束死循环了
    Thread-1结束死循环了
    Thread-0结束死循环了
    

    递归与非递归取组内对象

    public class Main5 {
    	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("run Method");
    					Thread.sleep(10000);
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		};
    		ThreadGroup groupB = new ThreadGroup(groupA, "B");
    		ThreadGroup[] groups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
    		//传入true取得其子组及子孙组
    		Thread.currentThread().getThreadGroup().enumerate(groups, true);
    		for (int i = 0; i < groups.length; i++) {
    			if (groups[i] != null) {
    				System.out.println(groups[i].getName());
    			}
    		}
    		System.out.println("------");
    		ThreadGroup[] groups2 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
    		Thread.currentThread().getThreadGroup().enumerate(groups2, false);
    		for (int i = 0; i < groups2.length; i++) {
    			if (groups2[i] != null) {
    				System.out.println(groups2[i].getName());
    			}
    			
    		}
    	}
    }
    

    控制台打印结果如下:

    A
    B
    ------
    A
    

    使线程具有顺序性

    public class MyThread extends Thread {
    	private Object lock;
    	private String showChar;
    	private int showNumberPosition;
    	private int printCount = 0;
    	volatile private static int addNumber = 1;
    	public MyThread(Object lock, String showChar, int showNumberPosition) {
    		super();
    		this.lock = lock;
    		this.showChar = showChar;
    		this.showNumberPosition = showNumberPosition;
    	}
    	@Override
    	public void run() {
    		try {
    			synchronized (lock) {
    				while (true) {
    					if (addNumber % 3 == showNumberPosition) {
    						System.out.println(Thread.currentThread().getName() + "-" + addNumber + "-" + showChar);
    						lock.notifyAll();
    						addNumber++;
    						printCount++;
    						if (printCount == 3) {
    							break;
    						}
    					}else {
    						lock.wait();
    					}
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	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();
    	}
    }
    
    

    控制台打印结果如下:

    Thread-0-1-A
    Thread-1-2-B
    Thread-2-3-C
    Thread-0-4-A
    Thread-1-5-B
    Thread-2-6-C
    Thread-0-7-A
    Thread-1-8-B
    Thread-2-9-C
    

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

    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 static void main(String[] args) {
        	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
            MyThread[] threadArray = new MyThread[10];
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i] = new MyThread(sdf, dateStringArray[i]);
            }
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i].start();
            }
    	}
    }
    

    运行程序,控制台打印结果如下:

    Exception in thread "Thread-3" Exception in thread "Thread-5" ThreadName=Thread-8报错了,日期字符串:2016-07-09,转换成的日期为:2016-07-08
    Exception in thread "Thread-1" Exception in thread "Thread-4" java.lang.NumberFormatException: empty String
    	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1020)
    	at java.lang.Double.parseDouble(Double.java:540)
    	at java.text.DigitList.getDouble(DigitList.java:168)
    	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
    	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    	at java.text.DateFormat.parse(DateFormat.java:355)
    ThreadName=Thread-6报错了,日期字符串:2016-07-07,转换成的日期为:2070-12-07
    ThreadName=Thread-2报错了,日期字符串:2016-07-03,转换成的日期为:0010-12-07
    ThreadName=Thread-7报错了,日期字符串:2016-07-08,转换成的日期为:0000-12-07
    	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
    Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "66E16E16E1"
    	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1250)
    	at java.lang.Double.parseDouble(Double.java:540)
    	at java.text.DigitList.getDouble(DigitList.java:168)
    	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
    	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    	at java.text.DateFormat.parse(DateFormat.java:355)
    	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
    java.lang.NumberFormatException: For input string: "66E"
    	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    	at java.lang.Long.parseLong(Long.java:441)
    	at java.lang.Long.parseLong(Long.java:483)
    	at java.text.DigitList.getLong(DigitList.java:194)
    	at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
    	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088)
    	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    	at java.text.DateFormat.parse(DateFormat.java:355)
    	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
    java.lang.NumberFormatException: For input string: "...7076"
    	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    	at java.lang.Long.parseLong(Long.java:430)
    	at java.lang.Long.parseLong(Long.java:483)
    	at java.text.DigitList.getLong(DigitList.java:194)
    	at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
    	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    	at java.text.DateFormat.parse(DateFormat.java:355)
    	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
    java.lang.NumberFormatException: For input string: "66E16E1"
    	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1250)
    	at java.lang.Double.parseDouble(Double.java:540)
    	at java.text.DigitList.getDouble(DigitList.java:168)
    	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
    	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    	at java.text.DateFormat.parse(DateFormat.java:355)
    	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
    

    解决方法1:

    public class DateUtil {
        public static String format(String formatPattern, Date date){
             return new SimpleDateFormat(formatPattern).format(date).toString();
        }
        
        public static Date parse(String formatPattern, String dateString) throws ParseException{
            return new SimpleDateFormat(formatPattern).parse(dateString);
        }
    }
    
    public class MyThread extends Thread {
        private String dateString;
    
        public MyThread(String dateString) {
            super();
            this.dateString = dateString;
        }
    
        @Override
        public void run() {
            try {
                Date dateRef = DateUtil.parse("yyyy-MM-dd", dateString);
                String newDateString = DateUtil.format("yyyy-MM-dd" ,dateRef).toString();
                if (!newDateString.equals(dateString)) {
                    System.out.println("ThreadName=" + this.getName()
                            +"报错了,日期字符串:" +dateString
                            +",转换成的日期为:"+newDateString);
                }else{
                	System.out.println("转换正确");
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
            MyThread[] threadArray = new MyThread2[10];
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i] = new MyThread(dateStringArray[i]);
            }
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i].start();
            }
    	}
    }
    
    

    运行程序,控制台打印结果如下:

    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    

    此时每个线程分别使用自己独立的SimpleDateFormat对象,不会出现线程安全问题。

    解决方法2:

    public class DateTools {
    	private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();
    	public static SimpleDateFormat getSimpleDateFormat(String dateParttern) {
    		SimpleDateFormat sdf = null;
    		sdf = t1.get();
    		if (sdf == null) {
    			sdf = new SimpleDateFormat(dateParttern);
    			t1.set(sdf);
    		}
    		return sdf;
    	}
    }
    
    public class MyThread extends Thread {
        private String dateString;
    
        public MyThread(String dateString) {
            super();
            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);
                }else{
                	System.out.println("转换正确");
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
            MyThread[] threadArray = new MyThread[10];
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i] = new MyThread(dateStringArray[i]);
            }
            for (int i=0; i<threadArray.length; i++) {
                threadArray[i].start();
            }
    	}
    }
    

    运行程序,控制台打印结果如下:

    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    转换正确
    

    线程中出现异常的处理

    在Java多线程中,可以对多线程中的异常进行“捕捉”,使用的是UncaughtExceptionHandler类。

    public class MyThread extends Thread {
    	@Override
    	public void run() {
    		String username = null;
    		System.out.println(username.hashCode());
    	}
    	
    	public static void main(String[] args) {
    		MyThread t1 = new MyThread();
    		t1.setName("线程1");
    		t1.setUncaughtExceptionHandler(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("线程2");
    		t2.start();
    	}
    }
    

    运行程序,控制台打印结果如下:

    Exception in thread "线程2" 线程1出现了异常
    java.lang.NullPointerException
    	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
    java.lang.NullPointerException
    	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
    

    setUncaughtExceptionHandler()是给指定的线程对象设置异常处理器。在Thread类中可以使用setDefaultUncaughtExceptionHandler()方法对所有线程对象设置异常处理器。

    public class MyThread extends Thread {
    	@Override
    	public void run() {
    		String username = null;
    		System.out.println(username.hashCode());
    	}
    	
    	public static void main(String[] args) {
    		MyThread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    					
    					@Override
    					public void uncaughtException(Thread t, Throwable e) {
    						System.out.println(t.getName() + "出现了异常");
    						e.printStackTrace();
    					}
    				});
    		MyThread t1 = new MyThread();
    		t1.setName("线程1");
    		t1.start();
    		MyThread t2 = new MyThread();
    		t2.setName("线程2");
    		t2.start();
    	}
    }
    

    运行程序,控制台打印结果如下:

    线程1出现了异常
    线程2出现了异常
    java.lang.NullPointerException
    	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
    java.lang.NullPointerException
    	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
    

    线程组内处理异常

    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 (true) {
    			System.out.println(Thread.currentThread().getName() + "死循环中");
    		}
    	}
    	
    	public static void main(String[] args) {
    		ThreadGroup group = new ThreadGroup("线程组1");
    		MyThread[] myThreads = new MyThread[10];
    		for (int i = 0; i < myThreads.length; i++) {
    			myThreads[i] = new MyThread(group, "线程" + i, "" + i);
    			myThreads[i].start();
    		}
    		MyThread myThread = new MyThread(group, "报错线程", "a");
    		myThread.start();
    	}
    }
    

    运行程序后,出错的线程抛出异常后停止,其他线程仍然正常执行。

    如果要使一个线程抛异常后同组内其他线程都停止执行可以做如下修改:

    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 com.umgsai.thread.thread71;
    
    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()) {
    			System.out.println(Thread.currentThread().getName() + "死循环中");
    		}
    	}
    	
    	
    	public static void main(String[] args) {
    		MyThreadGroup group = new MyThreadGroup("线程组1");
    		MyThread[] myThreads = new MyThread[10];
    		for (int i = 0; i < myThreads.length; i++) {
    			myThreads[i] = new MyThread(group, "线程" + i, "" + i);
    			myThreads[i].start();
    		}
    		MyThread myThread = new MyThread(group, "报错线程", "a");
    		myThread.start();
    	}
    }
    

    运行程序,报错线程抛出异常后,其他线程都停止了执行。


    线程异常处理的传递

    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));
    	}
    }
    
    public class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler {
    
    	@Override
    	public void uncaughtException(Thread t, Throwable e) {
    		System.out.println("对象的异常处理");
    		e.printStackTrace();
    	}
    
    }
    
    public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {
    
    	@Override
    	public void uncaughtException(Thread t, Throwable e) {
    		System.out.println("静态的异常处理");
    		e.printStackTrace();
    	}
    }
    
    public class Main {
    	public static void main(String[] args) {
    		MyThread myThread = new MyThread();
    		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
    		myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
    		myThread.start();
    	}
    }
    

    运行程序,控制台打印结果如下:

    对象的异常处理
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    

    对以上程序做如下修改:

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

    重新运行程序,控制台打印结果如下:

    静态的异常处理
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    

    继续修改以上代码:

    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();
    	}
    }
    
    public class Main {
    	public static void main(String[] args) {
    		MyThreadGroup group = new MyThreadGroup("我的线程组");
    		MyThread myThread = new MyThread(group, "我的线程");
    		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
    		myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
    		myThread.start();
    	}
    }
    

    运行程序,控制台打印结果如下:

    对象的异常处理
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    

    继续修改以上代码:

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

    运行程序,控制台打印结果如下:

    静态的异常处理
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    线程组的异常处理
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    

    继续修改以上代码:

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

    运行程序,控制台打印结果如下:

    Exception in thread "我的线程" 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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    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 com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
    
  • 相关阅读:
    远程接入系统的问题
    FastReport
    通用FASTREPORT打印模块及接口方法
    cxGrid控件过滤筛选后如何获更新筛选后的数据集
    Oracle Data Integrator 12c (12.1.2)新特性
    ODI 12c 安装
    Kafka面试题
    Hadoop面试题
    Spark面试题
    JAVA面试题-数组字符串基础
  • 原文地址:https://www.cnblogs.com/umgsai/p/5600111.html
Copyright © 2011-2022 走看看