源无极

导航

 

一、使线程具有有序性

正常的情况下线程运行是无序的,但是可以通过改造代码的方式使他们运行具有有序性。

 

package com.it.po.thread14;

public class MyThread7 extends Thread {
private Object lock;
private String showChar;
private  int showNumPosition;
private int printCount;
volatile private static int addNumber=1;
    public MyThread7(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("线程 "+Thread.currentThread().getName()
                     +" runCount "+addNumber+" "+showChar);
                     lock.notifyAll();
                     addNumber++;
                     printCount++;
                     if(printCount==3){//只有三条线程
                         break;
                     }
                    }else {//不是的先等着
                        lock.wait();
                    }
                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread14;
import com.it.po.thread05.Task1;
public class Run14 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        MyThread7 t1 = new MyThread7(lock,"A",1);
        MyThread7 t2 = new MyThread7(lock,"B",2);
        MyThread7 t3 = new MyThread7(lock,"C",0);
       t1.start();
       t2.start();
       t3.start();

    }
}

 

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

 

二、SimpleDateFormat 非线程安全

 类SimpleDateFormat主要负责日期的转化与格式化,但是在多线程环境

使用此类易造成数据转化及处理的不正确,因为SimpleDateFormat并不是线程安全。

 (一)出现的异常

package com.it.po.thread14;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread8 extends Thread {
private String dateString;
private SimpleDateFormat simpleDateFormat;
    public MyThread8(String dateString, SimpleDateFormat simpleDateFormat) {
        this.dateString = dateString;
        this.simpleDateFormat = simpleDateFormat;
    }

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

 

package com.it.po.thread14;
import java.text.SimpleDateFormat;
public class Run12 {
    public static void main(String[] args) throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String[] dataStringArray = new String[]{"2019-12-01","2019-12-02",
                "2019-12-03","2019-12-04","2019-12-05","2019-12-06",
                "2019-12-07","2019-12-08","2019-12-09","2019-12-10",};
        MyThread8[] thread8s = new MyThread8[10];
        for(int i=0;i<10;i++){
         thread8s[i]=new MyThread8(dataStringArray[i],format);
        }
        for(int i=0;i<10;i++){
            thread8s[i].start();
        }
    }
}

 

线程 Thread-0 报错了 日期字符串 2019-12-01 转化成日期 2019-12-05
线程 Thread-3 报错了 日期字符串 2019-12-04 转化成日期 2019-12-05
线程 Thread-2 报错了 日期字符串 2019-12-03 转化成日期 2019-12-05
线程 Thread-7 报错了 日期字符串 2019-12-08 转化成日期 2019-12-09
线程 Thread-1 报错了 日期字符串 2019-12-02 转化成日期 0001-12-10

 

(二)解决方案一

package com.it.po.thread14;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTools {
public static Date pare(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);
}
}

 

package com.it.po.thread14;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread9 extends Thread {
private String dateString;
private SimpleDateFormat simpleDateFormat;
    public MyThread9(String dateString, SimpleDateFormat simpleDateFormat) {
        this.dateString = dateString;
        this.simpleDateFormat = simpleDateFormat;
    }

    @Override
    public void run() {
        try {
            Date date = DateTools.pare("yyyy-MM-dd",dateString);
            String newDateString = DateTools.format("yyyy-MM-dd",date);
            if(!dateString.equals(newDateString)){
                System.out.println("线程 "+this.getName()+" 报错了 日期字符串 "+dateString
                +" 转化成日期 "+newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread14;
import java.text.SimpleDateFormat;
public class Run12 {
    public static void main(String[] args) throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String[] dataStringArray = new String[]{"2019-12-01","2019-12-02",
                "2019-12-03","2019-12-04","2019-12-05","2019-12-06",
                "2019-12-07","2019-12-08","2019-12-09","2019-12-10",};
        MyThread9[] threads = new MyThread9[10];
        for(int i=0;i<10;i++){
            threads[i]=new MyThread9(dataStringArray[i],format);
        }
        for(int i=0;i<10;i++){
            threads[i].start();
        }
    }
}

 

 无打印。

原理就是创建了多个SimpleDateFormat对象。

(三)、解决方案二

ThreadLock类能使线程绑定到指定的对象中,使用该类也可以

解决目前的问题

 

package com.it.po.thread14;
import java.text.SimpleDateFormat;
public class DateTools2 {
    private static ThreadLocal<SimpleDateFormat> t1 =new ThreadLocal<SimpleDateFormat>();
    public static SimpleDateFormat getSimpleDateFormat( String datePattern)   {
        SimpleDateFormat simpleDateFormat =null;
        simpleDateFormat=t1.get();
        if(simpleDateFormat==null){
            simpleDateFormat = new SimpleDateFormat(datePattern);
            t1.set(simpleDateFormat);
        }
        return  simpleDateFormat;
    }
}

 

package com.it.po.thread14;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread10 extends Thread {
private String dateString;
private SimpleDateFormat simpleDateFormat;
    public MyThread10(String dateString, SimpleDateFormat simpleDateFormat) {
        this.dateString = dateString;
        this.simpleDateFormat = simpleDateFormat;
    }
    @Override
    public void run() {
        try {
            Date date = DateTools2.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            String newDateString = DateTools2.getSimpleDateFormat("yyyy-MM-dd").format(date).toString();
            if(!dateString.equals(newDateString)){
                System.out.println("线程 "+this.getName()+" 报错了 日期字符串 "+dateString
                +" 转化成日期 "+newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
package com.it.po.thread14;
import java.text.SimpleDateFormat;
public class Run12 {
    public static void main(String[] args) throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String[] dataStringArray = new String[]{"2019-12-01","2019-12-02",
                "2019-12-03","2019-12-04","2019-12-05","2019-12-06",
                "2019-12-07","2019-12-08","2019-12-09","2019-12-10",};
        MyThread10[] threads = new MyThread10[10];
        for(int i=0;i<10;i++){
            threads[i]=new MyThread10(dataStringArray[i],format);
        }
        for(int i=0;i<10;i++){
            threads[i].start();
        }
    }
}

 

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

 

package com.it.po.thread14;

public class MyThread11 extends Thread {
    @Override
    public void run() {
        super.run();
      String username=null;
      System.out.println("username = "+username.hashCode());

    }
}

 

package com.it.po.thread14;

public class Run13 {
    public static void main(String[] args) throws InterruptedException {
        MyThread11 t1 = new MyThread11();
          t1.start();
    }
}

 

如何处理线程异常呢?

在多线程中使用UncaughtExceptionHandler 类从而对发生的异常进行有效的控制。

 

package com.it.po.thread14;

public class Run13 {
    public static void main(String[] args) throws InterruptedException {
        MyThread11 t1 = new MyThread11();
          t1.setName(" 线程t1 ");
          t1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
              @Override
              public void uncaughtException(Thread t, Throwable e) {
                  System.out.println("线程 "+t.getName() + " 出现异常了: ");
                  e.printStackTrace();
              }
          });
          t1.start();
        MyThread11 t2 = new MyThread11();
        t2.setName(" 线程t2 ");
        t2.start();
    }
}
Exception in thread " 线程t2 " java.lang.NullPointerException
    at com.it.po.thread14.MyThread11.run(MyThread11.java:8)
java.lang.NullPointerException
    at com.it.po.thread14.MyThread11.run(MyThread11.java:8)
线程  线程t1  出现异常了: 

 

setUncaughtExceptionHandler 方法对指定的线程对象设置默认的异常处理器。

 

在Thread类中还可以使用setDefaultUncaughtExceptionHandler  对所有线程对象设置异常

处理器。

package com.it.po.thread14;

public class Run15 {
    public static void main(String[] args) throws InterruptedException {
        MyThread11.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("线程 "+t.getName() + " 出现异常了: ");
                e.printStackTrace();
            }
        });
        MyThread11 t1 = new MyThread11();
        t1.setName(" 线程t1 ");
        t1.start();
        MyThread11 t2 = new MyThread11();
        t2.setName(" 线程t2 ");
        t2.start();
       
    }
}
线程  线程t1  出现异常了: 
线程  线程t2  出现异常了: 
java.lang.NullPointerException
    at com.it.po.thread14.MyThread11.run(MyThread11.java:8)
java.lang.NullPointerException
    at com.it.po.thread14.MyThread11.run(MyThread11.java:8)

 

四、线程组内处理异常

package com.it.po.thread14;

public class MyThread12 extends Thread {
    private String num;

    public MyThread12(ThreadGroup group,String name ,String num) {
        super(group,name);
        this.num = num;
    }

    @Override
    public void run() {
        super.run();
        int newNum = Integer.parseInt(num);
     while (true){
         System.out.println("线程死循环中 "+Thread.currentThread().getName());
     }
    }
}

 

package com.it.po.thread14;

public class Run16 {
    public static void main(String[] args) throws InterruptedException {
        ThreadGroup group = new ThreadGroup("我的线程组");
        MyThread12[] thread12s = new MyThread12[10];
        for(int i=0;i<10;i++){
            thread12s[i]=new MyThread12(group,"线程 "+(i+1),"1");
            thread12s[i].start();
        }
        MyThread12 myThread12 = new MyThread12(group, "报错线程 ", "a");
        myThread12.start();
    }
}

运行的时候虽然报错的线程 出现异常了,但是其他线程由于是while循环中

还会继续运行,像这样,线程组内一个线程出现异常后全部线程都停止,该如何呢

 

package com.it.po.thread14;

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.it.po.thread14;

public class MyThread13 extends Thread {
    private String num;

    public MyThread13(ThreadGroup group, String name , String num) {
        super(group,name);
        this.num = num;
    }

    @Override
    public void run() {
        super.run();
        int newNum = Integer.parseInt(num);
     while (this.isInterrupted()==false){
         System.out.println("线程死循环中 "+Thread.currentThread().getName());
     }
    }
}

 

package com.it.po.thread14;
public class Run17 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadGroup group = new MyThreadGroup("我的线程组");
        MyThread13[] thread12s = new MyThread13[10];
        for(int i=0;i<10;i++){
            thread12s[i]=new MyThread13(group,"线程 "+(i+1),"1");
            thread12s[i].start();
        }
        MyThread13 myThread12 = new MyThread13(group, "报错线程 ", "a");
        myThread12.start();
    }
}

 

 

 

 注意:使用自定义的java.lang.ThreadGroup线程组,并且重写  uncaughtException 

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

否则, public void uncaughtException(Thread t, Throwable e)  方法不执行。

 五、线程异常处理的传递。

 前面介绍了异常处理的方式,那么这些处理的方式如果放在一起运行,会怎么样?

 

package com.it.po.thread14;
public class MyThread14 extends Thread {
    private String num="a";
    public MyThread14() {
    }
    public MyThread14(ThreadGroup group,String name) {
        super(group,name);
    }

    @Override
    public void run() {
        super.run();
        int a = Integer.parseInt(num);
        System.out.println("在线程中打印。。。"+(a+1));

    }
}

 

package com.it.po.thread14;

public class MyThreadGroup14 extends ThreadGroup {
    public MyThreadGroup14(String name) {
        super(name);
    }
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        super.uncaughtException(t, e);
        System.out.println("线程组的异常处理。。");
        e.printStackTrace();
    }
}
package com.it.po.thread14;

public class ObjectUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("对象异常处理。。");
        e.printStackTrace();
    }
}
package com.it.po.thread14;

public class StaticUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("静态异常处理。。");
        e.printStackTrace();
    }
}
package com.it.po.thread14;
public class Run18 {
    public static void main(String[] args) throws InterruptedException {
        MyThread14 t = new MyThread14();
       t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
       Thread.setDefaultUncaughtExceptionHandler(new StaticUncaughtExceptionHandler());
       t.start();
    }
}

 

 

 

 

 对象异常运行

 

修改一

 

package com.it.po.thread14;
public class Run18 {
    public static void main(String[] args) throws InterruptedException {
        MyThread14 t = new MyThread14();
      // t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
       Thread.setDefaultUncaughtExceptionHandler(new StaticUncaughtExceptionHandler());
       t.start();
    }
}

 

 

 

 

 

 

 

修改二

 

package com.it.po.thread14;

public class Run18 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadGroup14 myThreadGroup14 = new MyThreadGroup14("我的线程组");
        MyThread14 t = new MyThread14(myThreadGroup14,"我的线程");
       t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
       Thread.setDefaultUncaughtExceptionHandler(new StaticUncaughtExceptionHandler());
       t.start();
    }
}

 

 

 修改三

package com.it.po.thread14;
public class Run18 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadGroup14 myThreadGroup14 = new MyThreadGroup14("我的线程组");
        MyThread14 t = new MyThread14(myThreadGroup14,"我的线程");
      // t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
       Thread.setDefaultUncaughtExceptionHandler(new StaticUncaughtExceptionHandler());
       t.start();
    }
}

 

 

posted on 2019-12-17 22:56  源无极  阅读(177)  评论(0)    收藏  举报