多线程注意事项和获取子线程何时都执行完毕

前言

最近一段时间在整公司项目里一个功能的优化,用到了多线程处理。期间也是踩了不少的坑,在这里想说下我遇到的问题和注意事项。以及怎样知道启动的那些多线程都处理完毕这些问题。

实现Runnable接口类需要注意事项

我这里用的多线程,是用了实现Runnable接口,这样的话,要比继承Thread类更加的灵活。毕竟类只能单继承,但可以多实现。

1.事务失效

我实现Runnable接口的类,是处理业务的handler类,在spring配置里面是默认给这些类添加事务的。所以我当时直接在这个类里面写了业务代码。到测试的时候发现,如果业务方法里报Runtime异常,这个类里面的一些更新方法居然不回滚,直接提交了。

当时也是试了很多方法,手动给这个类加事务的注解、开辟新事物,都不行。后来查阅资料,发现在Runnable实现类里,是不支持事务的。那我就新写了一个类,把主要的业务方法全放到那个类里,再测试,发现事务可以正常回滚了。

2.注解无效

在实现Runnable接口的类里,本来想用spring提供的@Autowired注解来自动注入类呢,发现在run方法里,调用注入的类,报空指针。后来明白,实现Runnable接口的类不受spring监管,所以spring的一些注解就不能使用了。

解决办法:

1.可以参考下面这样写,可以获得你想要用的类。

ApplicationContext ctx = new ApplicationContext();
ctx.getBean(你想要获取的类名.class);

  

2.那就是在调用多线程实现类之前,在其他类里用spring的一些注解,获得你想要的类,然后通过参数方式,传到多线程实现类里面。(我是采用的这个方式。)

如何知道多个线程都执行完毕了呢?

使用多线程,主要就是为了提高程序的运行效率。一般情况下,分配完线程,让那些线程去执行就行了,也不需要关心他们都什么时候执行完毕了。但是有些情况下,知晓那些线程都什么时候执行完毕,确实很有用。

我实现的那个功能就是放在定时器里面的,知晓定时器什么时候开始,什么时候执行完毕,在完毕的时候执行一些发邮件的一些功能,是很有用的。如果是单线程,那就直接把那些方法日志啥的放到最后执行就可以了。

但是开辟了多个线程,往往是多线程还在执行,主线程不等那些子线程,就先自己执行完了,这时候,放到最后执行的那些功能就不行了,因为子线程还没执行完,主线程就把最后的那些“收尾”功能给执行了,肯定不合适。

thread.Join方法,可以让交替执行的线程变成顺序的执行,但这样跟单线程就没啥区别了。

后来,我想了一个办法。代码如下:

//线程池
private ExecutorService threadPool;
//分配线程任务
for (int i=0; i<5; i++) {
     threadPool.execute(new RunHandler());
}
//关闭线程池,此时执行的线程不会立刻关闭,而是线程池不再接受新的线程请求了,线程执行完会被回收掉。
threadPool.shutdown();
while(true){
    if(threadPool.isTerminated()) {//判断线程是否执行完毕,不是就休眠主线程。
        //如果子线程们都执行完毕,就会进这个判断,然后会跳出这个循环。这样就达到了主线程等待子线程们
        //都执行完了,才去执行其他的代码。
        break;
    }
    Thread.sleep(1000);//主线程睡眠1秒
}
//这里写执行完毕的日志或者最后的“收尾”功能。

  

这个就是我目前使用的方法。当然,能实现这个功能的方法还有很多,我选的也是比较好实现容易理解,效率算是比较高的一种吧。

最后

以上就是我发现和解决的一些常见的问题。由于能力有限,如有错误,敬请谅解。

写好一个多线程的功能,以上那些注意事项往往根本不够。最主要的是解决多线程之间的冲突,如何避免多线程操作导致变量数据的错乱和引发的数据库保存数据的异常等问题。这些是值得推敲和反复琢磨的,加锁一般能解决这些问题,但是不合理的加锁和使用的加锁方式的不同,可能会导致多线程执行起来的效率不尽人意。

有时间,我会单独写一篇多线程避免冲突错误的文章,来供大家参考下。

原文地址:https://www.cnblogs.com/Simple-Object/p/10740790.html

时间: 2024-07-31 15:59:02

多线程注意事项和获取子线程何时都执行完毕的相关文章

C++拾遗--多线程:主线程与子线程的同步

C++拾遗--多线程:主线程与子线程的同步 前言 在多线程编程时,有时是需要要求主线程与子线程同步的. 正文 程序演示 下面的一个例子,演示了主线程与子线程之间的同步问题. 程序描述: 在主线程中,有一整型变量count,初始化为0.主线程把count的地址传递给开启的子线程,子线程打印获取的值,随后主线程递增count的值,再次开启另一个子线程,传递count的地址-- #include <stdio.h> #include <stdlib.h> #include <pro

python多线程获取子线程任务返回值

今天想实现多线程更新资产信息,所以使用到了threading,但是我需要每个线程的返回值,这就需要我在threading.Thread的基础上进行封装 def auto_asset(node): ret = salt.remote_grains_execution_sigle(node) asset_info={} asset_info['os']= ret[node]['oscodename'] asset_info['kernelrelease']= ret[node]['kernelrel

Java多线程--让主线程等待子线程执行完毕

使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用countDownLatch.await()方法非常简单的完成主线程的等待: public class ThreadWait { public static void main(String[] args) throws InterruptedException { int threadNumber

python多线程(等待)主线程和子线程的同步执行

#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time def fun(name, ls_name, front_thread = None): ''' 线程启动函数 通过front_thread来使用线程有序的运行 ''' time.clock() time.sleep(2) # 如果front_thread存在,则在front_thread运行完成后,才运行当前线程 if front_thread

C#子线程执行完后通知主线程(转)

其实这个比较简单,子线程怎么通知主线程,就是让子线程做完了自己的事儿就去干主线程的转回去干主线程的事儿.  那么怎么让子线程去做主线程的事儿呢,我们只需要把主线程的方法传递给子线程就行了,那么传递方法就很简单了委托传值嘛: 下面有一个例子,子线程干一件事情,做完了通知主线程 public class Program { //定义一个为委托 public delegate void Entrust(string str); static void Main(string[] args) { Ent

Java主线程等待所有子线程执行完毕再执行解决办法集

Java主线程等待所有子线程执行完毕在执行,其实在我们的工作中经常的用到,比如说主线程要返回一个响应用户的值,但这个值得赋值过程是由过个子线程来完成的(模拟一个实际开发的情景),所以主线程必须等待子线程执行完毕,再响应用户:否则,响应用户的是一个无意义的值. 那么如何确保所有的子线程执行完毕了.一般的有如下方法: 1  让主线程等待,或着睡眠几分钟.用Thread.sleep()或者TimeUnit.SECONDS.sleep(5); 如下: package andy.thread.tradit

【C/C++多线程编程之四】终止pthread线程

多线程编程之终止pthread线程  Pthread是 POSIX threads 的简称,是POSIX的线程标准.           终止线程似乎是多线程编程的最后一步,但绝不是本系列教材的结束.线程创建到线程终止,希望先给读者一个关于多线程编程的总体认识.           1.终止Pthread线程:pthread_exit()           參数:           ret:地址指针,本质上是返回值写入的地址.           终止线程是线程的主动行为,一个线程调用pth

在子线程中创建Handler和looper并与主线程进行交互

分析完上面那篇文章,基本理解了handler的实现原理,乘热打铁,这里我们利用handler原理,在子线程中创建一个handler和looper 可能很多面试时候问道,子线程中能不能new一个handler ? 答案是可以的,但是因为主线程系统默认在ActivityThread中已将帮我们创建好一个looper和MessagQueue,我们不需要手动去创建 (手动创建会出错,因为一个线程中默认只运行一个looper和MessageQueue,具体见ThreadLocal代码原理), 而子线程中没

Java多线程--让主线程等待所有子线程执行完毕

数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下 Java代码   long tStart = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "开始&