精华内容
下载资源
问答
  • 多线程抛出异常
    千次阅读
    2020-12-04 14:44:40

    ***特别重要,因为如果程序中使用了多线程,那么这个异常处理不好的话,无法捕捉异常,可能会导致系统奔溃,并且查询不到问题

    public class CantCatchDirectly implements Runnable{
        public static void main(String[] args) throws InterruptedException {
            //try catch 只能捕获线程内的异常
            try{
                new Thread(new CantCatchDirectly(),"myThread-1").start();
                Thread.sleep(300);
                new Thread(new CantCatchDirectly(),"myThread-2").start();
                Thread.sleep(300);
                new Thread(new CantCatchDirectly(),"myThread-3").start();
                Thread.sleep(300);
                new Thread(new CantCatchDirectly(),"myThread-4").start();
            }catch (RuntimeException e){
                System.out.println("Caught Exception.");
            }
        }
        @Override
        public void run() {
            try{
                throw new RuntimeException();
            }catch (RuntimeException e){
                System.out.println("Caught Exception.");
            }
        }
    }

    以上代码运行的结果是?

    按道理来说应该是Caught Exception. 遇到异常直接抛出,并且程序终止

    但是结果是

    Caught Exception.
    Caught Exception.
    Caught Exception.
    Caught Exception.

    所以使用多线程之后,异常一定不要随意书写

    主线程可以轻松发现异常,子线程却不行

    子线程异常无法用传统方式捕获

    不能直接捕获的后果、提高健壮性

     

    两个解决方案:

    1.手动在每个run方法里进行try catch(不建议,因为要在每一个run方法里加,而且不知道异常的类型)

    2.利用UncaughtExceptionHandler

    void uncaughtException(Thread t,Throwable e)

    异常处理器的调用策略

    使用UncaughtExceptionHandler就能捕捉到异常

    /**
     * 自己的MyUncaughtExceptionHandler
     */
    public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
        private String name;
    
        public MyUncaughtExceptionHandler(String name) {
            this.name = name;
        }
    
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            Logger logger = Logger.getAnonymousLogger();
            logger.log(Level.WARNING,"线程异常,终止啦"+t.getName(),e);
            System.out.println(name+"捕获了异常"+t.getName()+"异常"+e);
        }
    }

     

    更多相关内容
  • //设置setUncaughtExceptionHandler就能将线程内的异常抛出,否则只会存放在日志或者什么的 public class ThreadThrowExcption { public static void main(String[] args) { Thread t1 = new Thread(() -> { ...
    //设置setUncaughtExceptionHandler就能将线程内的异常抛出,否则只会存放在日志或者什么的
    public class ThreadThrowExcption {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                int a =1/0;
            });
            t1.setUncaughtExceptionHandler((thread,throwable)->{  
                System.out.println(throwable);
            });
            t1.start();
        }
    }
    
    展开全文
  • 多线程中一个线程抛出异常(不捕获);主线程及其他子线程如何表现 结论: 语言 主线程 子线程 C++ 挂死 挂死 Java 继续运行 继续运行 C++ code #include <iostream> #...

    进程与多线程

    多线程中一个线程抛出异常(不捕获);主线程及其他子线程如何表现

    • 结论
    语言主线程子线程
    C++挂死挂死
    Java继续运行继续运行
    • 原因
      java:存在用户线程(User Thread)和守护线程(Daemon Thread),当所有用户线程都退出了,守护线程退出,进而应用程序退出;这就是为什么"main线程"退出后,其他线程还正在运行。也是其他"子线程"被异常终止了或者退出了,其他线程正常运行。

      c++:main属于主进程,当子线程抛出异常时,最后抛到主线程中,导致主进程crash,进而结束应用程序,相应的Thread被销毁(thread对象被销毁)。

    C++ code

    #include <iostream>
    #include <thread>
    #include <chrono>
    
    void thread1_func() {
        int i = 0;
        while(true) {
            std::this_thread::sleep_for (std::chrono::seconds(1));
            std::cout << "thread1 i: " << i++ << "\n";
            if (i == 3) {
                throw 1;
            }
        }
    }
    
    void thread2_func() {
        int i = 0;
        while(true) {
            std::this_thread::sleep_for (std::chrono::seconds(1));
            std::cout << "thread2 i: " << i++ << "\n";
        }
    }
    
    
    int main() {
        std::cout << "Main thread start:spawning 2 threads... \n";
        std::thread t1 (thread1_func);
        std::thread t2 (thread2_func);
    
        t1.join();
        t2.join();
    
        std::cout << "Main thread end\n";
        return 0;
    }
    
    

    运行结果:

    Main thread start:spawning 2 threads…
    thread1 i: thread2 i: 00
    thread1 i: 1
    thread2 i: 1
    thread1 i: 2
    thread2 i: 2
    terminate called after throwing an instance of ‘int’
    Aborted (core dumped)

    java代码:

    public class ThreadDemo {
    
    	public static void main(String[] args) {
    
    		System.out.println("Main Thread start");
    
    		// TODO Auto-generated method stub
    		Thread t1 = new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				// TODO Auto-generated method stub
    				int i = 0;
    				while(true) {
    					System.out.println("Thread1 i: "+(i++));
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    					if (i == 3) {
    						throw new RuntimeException();
    					}
    				}
    			}
    		});
    
    		Thread t2 = new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				// TODO Auto-generated method stub
    				int i = 0;
    				while(true) {
    					System.out.println("Thread2 i: "+(i++));
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
    			}
    		});
    
    		t2.start();
    		t1.start();
    
    		try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    
    		System.out.println("Main Thread end");
    
    	}
    
    }
    

    运行结果:

    Thread2 i: 1
    Main Thread end
    Thread1 i: 1
    Thread2 i: 2
    Thread1 i: 2
    Thread2 i: 3
    Exception in thread “Thread-0” java.lang.RuntimeException
    at ThreadDemo$1.run(ThreadDemo.java:26)
    at java.lang.Thread.run(Unknown Source)
    Thread2 i: 4
    Thread2 i: 5
    Thread2 i: 6
    Thread2 i: 7
    Thread2 i: 8
    Thread2 i: 9
    … …

    展开全文
  • 在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉,通过此篇文章给大家分享Java多线程多线程异常捕捉,需要的朋友可以参考下
  • java多线程程序中所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的...但是无法避免的是unchecked exception,也就是RuntimeException,当抛出异常时子线程会结束,但不会影响主线程
  • 线程池正常运行的情况下,如果忽然某条线程执行任务时,抛出异常,这个时候线程池会怎么处理呢? 准备测试代码(测试代码需要jdk1.8以上) public class ThreadThrowsExceptionTest { public static void main...

    线程池正常运行的情况下,如果忽然某条线程执行任务时,抛出了异常,这个时候线程池会怎么处理呢?
    准备测试代码(测试代码需要jdk1.8以上)

    public class ThreadThrowsExceptionTest {
        public static void main(String[] args) {
            ExecutorService executorService = new ThreadPoolExecutor(5, 5,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(), new DefaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy());
            executorService.submit(() -> {
                System.out.println("线程" + Thread.currentThread().getName() + "准备抛空指针异常了");
                throw new NullPointerException("线程抛出空指针啦");
            });
            IntStream.range(0, 4).forEach(index -> executorService.submit(() -> System.out.println("线程" + Thread.currentThread().getName() + "执行了任务" + index)));
    
        }
    
        //这里借用了Executors中DefaultThreadFactory,进行了简单修改,方便测试
        static class DefaultThreadFactory implements ThreadFactory {
            private static final AtomicInteger poolNumber = new AtomicInteger(1);
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            DefaultThreadFactory() {
                SecurityManager s = System.getSecurityManager();
                group = (s != null) ? s.getThreadGroup() :
                        Thread.currentThread().getThreadGroup();
                namePrefix = "pool-" +
                        poolNumber.getAndIncrement() +
                        "-thread-";
            }
            public Thread newThread(Runnable r) {
                Thread t = new Thread(group, r,
                        namePrefix + threadNumber.getAndIncrement(),
                        0);
                System.out.println("创建线程了" + t.getName());
                if (t.isDaemon())
                    t.setDaemon(false);
                if (t.getPriority() != Thread.NORM_PRIORITY)
                    t.setPriority(Thread.NORM_PRIORITY);
                return t;
            }
        }
    
    }
    

    这里的DefaultThreadFactory借用了Executors中DefaultThreadFactory的源码,进行了简单修改,方便我们调试时查看创建的线程信息。例子中提交了4个正常任务,1个抛异常的任务。执行情况如下

    创建线程了pool-1-thread-1
    线程pool-1-thread-1准备抛空指针异常了
    创建线程了pool-1-thread-2
    创建线程了pool-1-thread-3
    创建线程了pool-1-thread-4
    线程pool-1-thread-2执行了任务0
    线程pool-1-thread-3执行了任务1
    创建线程了pool-1-thread-5
    线程pool-1-thread-4执行了任务2
    线程pool-1-thread-5执行了任务3
    

    线程池创建了5条工作线程,正常执行了5个任务,其中一个抛出异常也没有影响其他工作线程,似乎线程池没有进行任何处理。
    由于Future获取异常的时机是在调用get方法时,这里需要我们稍稍改下代码

    public class ThreadThrowsExceptionTest {
        public static void main(String[] args) {
            ExecutorService executorService = new ThreadPoolExecutor(5, 5,
                    60L, TimeUnit.MINUTES,
                    new LinkedBlockingQueue<Runnable>(), new DefaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy());
            //这里改为调用execute
            executorService.execute(() -> {
                System.out.println("线程" + Thread.currentThread().getName() + "准备抛空指针异常了");
                throw new NullPointerException("线程抛出空指针啦");
            });
            IntStream.range(0, 4).forEach(index -> executorService.submit(() -> System.out.println("线程" + Thread.currentThread().getName() + "执行了任务" + index)));
    
        }
    
        ...
    
    }
    

    执行结果如下

    创建线程了pool-1-thread-1
    线程pool-1-thread-1准备抛空指针异常了
    创建线程了pool-1-thread-2
    Exception in thread "pool-1-thread-1" java.lang.NullPointerException: 线程抛出空指针啦
    	at com.example.homework.thread.ThreadThrowsExceptionTest.lambda$main$0(ThreadThrowsExceptionTest.java:20)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	at java.lang.Thread.run(Thread.java:745)
    创建线程了pool-1-thread-3
    创建线程了pool-1-thread-4
    创建线程了pool-1-thread-5
    线程pool-1-thread-4执行了任务1
    线程pool-1-thread-3执行了任务0
    创建线程了pool-1-thread-6
    线程pool-1-thread-5执行了任务2
    线程pool-1-thread-6执行了任务3
    

    这里出现了pool-1-thread-6!看来线程池在线程执行异常后新创建了一条线程。
    那么具体原因需要跟踪源码看一下

    public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> ftask = newTaskFor(task, null);
            //这里调用的是execute方法
            execute(ftask);
            return ftask;
        }
    

    由于submit方法中也是调用execute方法,所以我们只需要关注execute方法实现,execute方法细节如下

    public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
          	
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
            	//添加线程的主要方法
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }
    
    private boolean addWorker(Runnable firstTask, boolean core) {
            ...
            boolean workerStarted = false;
            boolean workerAdded = false;
            Worker w = null;
            try {
            	//这里通过Worker包装task
                w = new Worker(firstTask);
                final Thread t = w.thread;
                if (t != null) {
                    final ReentrantLock mainLock = this.mainLock;
                    mainLock.lock();
                    try {
                        // Recheck while holding lock.
                        // Back out on ThreadFactory failure or if
                        // shut down before lock acquired.
                        int rs = runStateOf(ctl.get());
    
                        if (rs < SHUTDOWN ||
                            (rs == SHUTDOWN && firstTask == null)) {
                            if (t.isAlive()) // precheck that t is startable
                                throw new IllegalThreadStateException();
                            workers.add(w);
                            int s = workers.size();
                            if (s > largestPoolSize)
                                largestPoolSize = s;
                            workerAdded = true;
                        }
                    } finally {
                        mainLock.unlock();
                    }
                    if (workerAdded) {
                    	//线程开始执行
                        t.start();
                        workerStarted = true;
                    }
                }
            } finally {
                if (! workerStarted)
                    addWorkerFailed(w);
            }
            return workerStarted;
        }
    

    这里没有对执行的情况做处理,那就只有继续跟踪Worker的代码

    private final class Worker
            extends AbstractQueuedSynchronizer
            implements Runnable
        {
            ...
            Worker(Runnable firstTask) {
                setState(-1); // inhibit interrupts until runWorker
                this.firstTask = firstTask;
                this.thread = getThreadFactory().newThread(this);
            }
    
            /** Delegates main run loop to outer runWorker  */
            public void run() {
            	//执行线程的关键方法
                runWorker(this);
            }
    
    final void runWorker(Worker w) {
            Thread wt = Thread.currentThread();
            Runnable task = w.firstTask;
            w.firstTask = null;
            w.unlock(); // allow interrupts
            boolean completedAbruptly = true;
            try {
                while (task != null || (task = getTask()) != null) {
                    w.lock();
                    // If pool is stopping, ensure thread is interrupted;
                    // if not, ensure thread is not interrupted.  This
                    // requires a recheck in second case to deal with
                    // shutdownNow race while clearing interrupt
                    if ((runStateAtLeast(ctl.get(), STOP) ||
                         (Thread.interrupted() &&
                          runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                        wt.interrupt();
                    try {
                        beforeExecute(wt, task);
                        Throwable thrown = null;
                        try {
                            task.run();
                        } catch (RuntimeException x) {
                            thrown = x; throw x;
                        } catch (Error x) {
                            thrown = x; throw x;
                        } catch (Throwable x) {
                            thrown = x; throw new Error(x);
                        } finally {
                            afterExecute(task, thrown);
                        }
                    } finally {
                        task = null;
                        w.completedTasks++;
                        w.unlock();
                    }
                }
                completedAbruptly = false;
            } finally {
                processWorkerExit(w, completedAbruptly);
            }
        }
    

    主要执行的细节方法在runWorker中,而对于发生异常的处理有两个地方afterExecute,processWorkerExit。afterExecute是留给子类实现的,processWorkerExit的源码如下

    /**
         * Performs cleanup and bookkeeping for a dying worker. Called
         * only from worker threads. Unless completedAbruptly is set,
         * assumes that workerCount has already been adjusted to account
         * for exit.  This method removes thread from worker set, and
         * possibly terminates the pool or replaces the worker if either
         * it exited due to user task exception or if fewer than
         * corePoolSize workers are running or queue is non-empty but
         * there are no workers.
         *
         * @param w the worker
         * @param completedAbruptly if the worker died due to user exception
         */
        private void processWorkerExit(Worker w, boolean completedAbruptly) {
        	//如果发生异常,completedAbruptly值为初始化值true,这里会减少目前的工作线程数,目的是为了排除当前发生异常的线程
            if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
                decrementWorkerCount();
    
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                completedTaskCount += w.completedTasks;
                workers.remove(w);
            } finally {
                mainLock.unlock();
            }
    
            tryTerminate();
    
            int c = ctl.get();
            if (runStateLessThan(c, STOP)) {
                if (!completedAbruptly) {
                    int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                    if (min == 0 && ! workQueue.isEmpty())
                        min = 1;
                    if (workerCountOf(c) >= min)
                        return; // replacement not needed
                }
                //这里会新增一个工作线程
                addWorker(null, false);
            }
        }
    

    至此终于线程池的发生异常的处理过程大致就清楚了,从此例可以看出,ThreadPoolExecutor默认使用的是懒加载的方式,没有一开始就初始化指定核心线程数量的线程。而Worker同时也是装饰模式的一种应用,给Tread增加了一些额外的处理逻辑,使其使用起来更加灵活。

    展开全文
  • 这个问题坑了很Java程序员,若你能想到锁...无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我更喜欢同步块,因为它不用我花费精力去释放锁,该功能可以在finally block里释放锁实现。
  • Java中如何捕获其他线程抛出异常

    千次阅读 2018-12-28 13:40:49
    如Java中另一个线程抛出异常 可以使用公共静态接口Thread.UncaughtExceptionHandler完成。 Thread.UncaughtExceptionHandler是当线程因未捕获的异常而突然终止时调用的处理程序接口。 当一个线程由于未捕获的...
  • 昨天开始看《Java多线程编程核心技术》一书。记录一些所学:1.通过查看“Windows资源管理器”中的列表,完全可以将运行在内存中的.exe文件理解成一个线程,线程是受操作系统管理的基本运行单元。2.非线程安全:指多...
  • 示例代码 public class TestMain implements Runnable { //格式化 static SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void run() { //让线程Thread-0...
  • 如果你的程序抛了异常,你是怎么处理的呢?等待程序崩溃退出?还是进行补救?如果是做 UI 开发,很容易就...但是,如果是后台线程抛出异常呢?并没有 Dispatcher 可以用。所以我们就束手就擒让程序自己退出吗?WPF 和
  • java多线程中的异常处理

    千次阅读 2019-10-18 21:37:00
    首先,我们要知道,在Java中,线程中的异常是不能抛出到调用该线程的外部方法中捕获的。 为什么不能抛出到外部线程捕获? 因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”...
  • java抛出异常是怎么回事?

    千次阅读 多人点赞 2021-02-13 00:49:01
    一、Java异常的基础知识异常是程序中的一些错误,...如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常。有些异常需要做处理,有些则不需要捕获处理,后面...
  • 开发自己的项目有一段时间了,因为是个长时间跑的服务器端程序,所以异常处理显得尤为重要。对于异常的抓取和日志(狭义上的日志)的分析一点都不能落下。我们使用了Java自带的Executor模块,我只是稍微看了下...
  • 线程抛出异常后,synchronized锁会不会主动释放 —笔记 思路: 创建两个线程分别访问同一对象的不同方法,在第一个方法主动抛出异常,如果第二个方法正常执行,则会主动释放,反之亦然。 代码: public class ...
  • Python异常处理和多线程

    千次阅读 2017-06-30 09:38:46
    由于每个进程只要干一件事,所以,一个进程只要有一个线程,当然,想 Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多线程是一样的,也是由操作系统在多个线程之间快速切换,让每个...
  • 近期在使用多线程时遇到了主线程无法捕获子线程抛出异常问题,这里记录一下解决的办法。 需求 将某一指定目录下所有的文件(包含子目录下的文件)中所有被$[]$字符包裹起来的变量替换成指定的值,这是一个典型的io...
  • 因此:受检异常实际可以理解为需要被手动捕获的异常,如B方法中主动抛出异常,若方法A中调用B方法,也需要手动捕获该受检异常 2.非受检异常 非受检异常,实际就是RuntimeException运行时异常,在定义方
  • 多线程中的异常处理

    千次阅读 2019-07-28 19:51:40
    Thread类run方法不会将异常抛出 如: 主线程: public static void main(String[] args) { try{ Thread t=new Thread(new Task()); t.start(); }catch (Exception e){ System.o...
  • 分段执行业务时需要执行某段sql语句,由于是线程执行个sql,线程之间需要使用一些读锁,若发生异常需要释放锁,结果某个线程的sql出现了错误,后台没有打印错误日志。 List<ImportModel> query = ...
  • java线程异常处理方法

    2021-03-05 20:33:52
    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.R...
  • 作者 |why技术来源 | why技术(ID:hello_hi_why)一道面试题我一年前写过这篇文章《有的线程它死了,于是它变成一道面试题》,这是早期作品,遣词造句,排版行文都有一点...
  • java线程中能不能捕获异常

    千次阅读 2018-12-28 22:01:51
    不能 ,如果要捕获异常怎么处理。我们要实现UncaughtExceptionHandler这个接口来捕获抛出的异常。 由于Java线程的本质特征,当...不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个...
  • 首先明确线程代码的边界。其实很简单,Runnable接口的run... 而所有的具体线程都实现这个方法,所以这里就明确了一点,线程代码不能抛出任何checked异常。所有的线程中的checked异常都只能被线程本身消化掉。:) 这样本
  • 原因: 当大量抛出运行时异常时,系统肯定存在问题,会影响系统吞吐量
  • 捕获Java线程池执行任务抛出异常

    千次阅读 2019-03-11 21:58:55
    Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { public abstract void run...
  • 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢?public void add(int index, E element){if(size >= elements.length) {throw new ...
  • C++抛出异常

    千次阅读 2018-05-29 01:51:34
    #include&lt;iostream&gt; #include&lt;cmath&gt; using namespace std;...全局变量,在多线程中易发生竞争。而且,当错误发生的时候,上级函数要出错处理,层层上报,造成过多的出错处...
  • 建议66:正确捕获多线程中的异常

    千次阅读 2016-09-07 10:50:19
    建议66:正确捕获多线程中的异常 多线程异常处理需要采用特殊的方式。一下这种方式会存在问题: try { Thread t = new Thread((ThreadStart)delegate { throw new Except
  • 文章目录背景方案设计ThreadPool类使用方法简单设计一个会抛出异常的函数最终方案 背景 随着数据量增多,业务中处理该类数据的模块需要从串行处理升级成多线程处理。 原流程中只有部分流程需要多线程优化,而多线程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 343,218
精华内容 137,287
关键字:

多线程抛出异常