一 体系化深入学习并发编程由简入繁系统梳理并发知识点(12)


所以要使用该接口,我们需要设置一个自定义的异常处理器,当发生异常时,就调用我们设置的异常处理器
下面我们就来自定义一个全局异常处理器:
public class OwnUnCaughtExceptionHandler implements Thread.UncaughtExceptionHandler {@Override//如果捕获到异常就打印这句话public void uncaughtException(Thread t, Throwable e) {System.out.println("自定义异常处理器捕获到"+t.getName()+"线程中的"+e.getMessage());}}
这里使用上面设置的异常处理器,并且在主线程内设置一个异常,不用try/catch方法来执行看看
public class UseOwnUnCaughtExceptionHandler {public static void main(String[] args) {//使用自定义的全局异常处理器Thread.setDefaultUncaughtExceptionHandler(new OwnUnCaughtExceptionHandler());new Thread(()->{throw new RuntimeException("子线程异常");}).start();//主线程的异常int i= 1/0;}}
可以看到,主线程和子线程的异常都被捕获到了
自定义异常处理器捕获到main线程中的/ by zero自定义异常处理器捕获到Thread-0线程中的子线程异常
多线程的利与弊 线程安全问题
多线程虽然会为程序带来便利,但是同时有可能来带线程安全的问题,所以我们需要避免多线程带来的线程安全问题,去其糟粕,取其精华
结果错误的线程安全问题
这是线程安全问题中经典的a++问题:
private static int index=0;public static void main(String[] args) throws InterruptedException {Runnable r = new Runnable() {@Overridepublic void run() {for (int i = 0; i <10000; i++) {index++;}}};Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(index);}
两个线程都来对index进行+1操作,最后打印index
打印的结果总是波动的,有时是20000,多数时候少于20000
这是为什么呢?
因为index++这行指令不是原子性操作
有关知识在关于JMM时进行总结
获取到index对index进行+1操作赋值index
但单线程的情况下没有问题,但是多线程就会出现问题了
举个例子:当前index是1
可能线程1执行到第二步的时候,在它的线程工作空间内部将index+1,还没有写回时,突然时间片没有了 。
而线程1在等待CPU资源的同时,线程2也拿到index也是1(线程1还没写回),线程2进行+1操作后,写回index=2
而线程1这时拿到了CPU资源,继续操作,写回index=2
也就是两个线程都执行了++操作,但是实际数据只+1
线程的活性故障
由于资源短缺或者程序自身的问题缺陷导致线程处于非状态,或者线程处于状态但是并不能继续运行任务的故障,就被成为线程活性故障
死锁
两个或多个线程都在相互等待对方的条件,而导致的永久性等待,就被称为死锁 。用一个成语来形容:鹬蚌相争
鹬和蚌都在等待对方先放开,最后导致谁也不放开谁
产生死锁的必要条件:
下面是一个简单的死锁实现
public static void main(String[] args) {Object lock1 = new Object();Object lock2 = new Object();new Thread(()->{synchronized (lock1){try {System.out.println(Thread.currentThread().getName()+"获取到锁1");TimeUnit.SECONDS.sleep(1);synchronized (lock2){System.out.println(Thread.currentThread().getName()+"获取到锁2");}} catch (InterruptedException e) {e.printStackTrace();}}},"线程1").start();new Thread(()->{synchronized (lock2){try {System.out.println(Thread.currentThread().getName()+"获取到锁2");TimeUnit.SECONDS.sleep(1);synchronized (lock1){System.out.println(Thread.currentThread().getName()+"获取到锁1");}} catch (InterruptedException e) {e.printStackTrace();}}},"线程2").start();}