有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已!

此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情。而使用线程的话将会存在这种问题:

主线程启动全部子线程并发运行后主线程就直接返回了,导致外部函数判读整个大的事情完毕了,可是实际上并没有完毕!

针对以上情况我想我会採用多线程方式运行同一时候解决主线程等待子线程的问题。如图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl1anVlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

在这里我使用Java进行案例分析。

首先建立一个线程管理类。用于启动全部子线程和等待全部子线程完毕。在这里不使用休眠一段时间后循环检測的方式(消耗CUP同一时候消耗时间,全部完毕时间不够及时等缺点)。而是使用等待临界值的方式。

ThreadManager.java例如以下:

public class ThreadManager implements NotifyInterface {
private final Object mLock = new Object();
private int mCount = 0;
private int endCount = 0; public ThreadManager(int count) {
System.out.println("Manager In."); this.mCount = count; this.addThread(); synchronized (mLock) {
while (true) {
if (checkEnd())
break;
try {
mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} System.out.println("Manager Out.");
} private void addThread() {
System.out.println("Manager addThread()."); for (int i = 1; i <= mCount; i++) {
ThreadDoThing dThread = new ThreadDoThing(i, "T" + i, this);
// Start
dThread.start();
} } private boolean checkEnd() {
boolean bFlag = false;
bFlag = endCount >= mCount; System.out.println("Manager checkEnd().Return is:" + bFlag); return bFlag;
} @Override
public void runEnd() {
synchronized (mLock) {
++endCount; mLock.notifyAll();
}
}
}

此类集成自:NotifyInterface接口,NotifyInterface是用于子线程通知主线程自己已经完毕工作所用类。ThreadManager实例化时将传入一个int值,用于设置启动的子线程数,当然这里是为了简介所以採用的这种方式,实际情况可能更加复杂。

在实例化后  进入构造方法,此时将会启动子线程,启动后进入循环等待中,当检測到全部子线程完毕时就退出循环,没有就将进入临界值等待,直到通过接口通知主线程完毕时将会通知临界值一次。此时循环将会运行一次。假设不满足退出条件将继续等待临界值。直到满足为止。

NotifyInterface接口例如以下:

public interface NotifyInterface {

	public abstract void runEnd();

}

測试用的子线程ThreadDoThing.java例如以下:

public class ThreadDoThing extends Thread {
private NotifyInterface mInterface = null;
private int mId = 0;
private String mArgs = null; public ThreadDoThing(int id, String args, NotifyInterface iface) {
this.mId = id;
this.mArgs = args;
this.AddInterface(iface);
} public void AddInterface(NotifyInterface iface) {
this.mInterface = iface;
} @Override
public void run() {
System.out.println("ThreadDoThing Id is:" + this.mId + " Args is:" + this.mArgs);
System.out.println(this.mId + ":Doing..."); int sleepTime = (int) (Math.random() * 1000); try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.mId + ":SleepTime is:" + sleepTime); this.notifyEnd(); System.out.println(this.mId + ":Do End.");
} private void notifyEnd() {
if (this.mInterface != null)
this.mInterface.runEnd(); System.out.println(this.mId + ":Notify End.");
}
}

此类继承自Thread类,可直接重写Run()方法完毕所做工作。

在工作中,我使用了随机一个1s内的休眠来取代所做工作的时间。完毕后调用接口通知完毕。

測试方法例如以下:

	/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadManager manager = new ThreadManager(10);
}

測试结果:

Manager In.
Manager addThread().
ThreadDoThing Id is:1 Args is:T1
ThreadDoThing Id is:2 Args is:T2
2:Doing...
1:Doing...
ThreadDoThing Id is:3 Args is:T3
ThreadDoThing Id is:4 Args is:T4
3:Doing...
4:Doing...
ThreadDoThing Id is:5 Args is:T5
5:Doing...
ThreadDoThing Id is:6 Args is:T6
Manager checkEnd().Return is:false
ThreadDoThing Id is:8 Args is:T8
ThreadDoThing Id is:7 Args is:T7
8:Doing...
ThreadDoThing Id is:9 Args is:T9
9:Doing...
6:Doing...
ThreadDoThing Id is:10 Args is:T10
7:Doing...
10:Doing...
3:SleepTime is:111
3:Notify End.
3:Do End.
Manager checkEnd().Return is:false
5:SleepTime is:142
5:Notify End.
Manager checkEnd().Return is:false
5:Do End.
4:SleepTime is:199
4:Notify End.
Manager checkEnd().Return is:false
4:Do End.
7:SleepTime is:342
7:Notify End.
Manager checkEnd().Return is:false
7:Do End.
10:SleepTime is:346
10:Notify End.
Manager checkEnd().Return is:false
10:Do End.
6:SleepTime is:397
6:Notify End.
Manager checkEnd().Return is:false
6:Do End.
9:SleepTime is:468
9:Notify End.
Manager checkEnd().Return is:false
9:Do End.
1:SleepTime is:475
1:Notify End.
Manager checkEnd().Return is:false
1:Do End.
2:SleepTime is:686
Manager checkEnd().Return is:false
2:Notify End.
2:Do End.
8:SleepTime is:828
8:Notify End.
Manager checkEnd().Return is:true
8:Do End.
Manager Out.

实际情况可能更加复杂。甚至子线程下还有很多其它的子线程!

详细情况大家能够衍生考虑,检測是否所有返回也能够有多种方式甚至设置加入一个定时器之类的。

以后有时间画一个具体点的图!

[Java][Android] 多线程同步-主线程等待全部子线程完毕案例的更多相关文章

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

    数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis() ...

  2. java主线程等待所有子线程执行完毕在执行(常见面试题)

    java主线程等待所有子线程执行完毕在执行(常见面试题) java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个 ...

  3. java主线程结束和子线程结束之间的关系

    (一)Main线程是个非守护线程,不能设置成守护线程. 这是因为,main线程是由java虚拟机在启动的时候创建的.main方法开始执行的时候,主线程已经创建好并在运行了.对于运行中的线程,调用Thr ...

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

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  5. java多线程实现主线程等待子线程执行完问题

    本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...

  6. Java主线程等待所有子线程执行完毕再执行解决办法(转)

    方法一: Thread.join()方法,亲测可行,thread.join()方法 Vector<Thread> ts = new Vector<Thread>(); for  ...

  7. Java中主线程如何捕获子线程抛出的异常

    首先明确线程代码的边界.其实很简单,Runnable接口的run方法所界定的边界就可以看作是线程代码的边界.Runnable接口中run方法原型如下: public void run(); 而所有的具 ...

  8. iOS开发之GCD同步主线程、异步主线程

    /** 在主线程执行block */ + (void)gs_synExecuteOnMainThread:(void (^)(void))block { if ((nil == block) || ( ...

  9. c/c++中主线程退出,子线程也会退出

    #include <windows.h> #include <process.h> /* _beginthread, _endthread */ #include <io ...

随机推荐

  1. java线程池 多线程 搜索包含关键字的文件路径

    package org.jimmy.searchfile20180807.main; public class ThreadMain implements Runnable{ private int ...

  2. 雷林鹏分享:PHP Secure E-mails

    在上一节中的 PHP e-mail 脚本中,存在着一个漏洞. PHP E-mail 注入 首先,请看上一章中的 PHP 代码: if (isset($_REQUEST['email'])) { // ...

  3. RabbitMQ之项目中实战

    说了那么多,还不是为了在项目中进行实战吗,在实践中检验真理,不然我学他干嘛,不能解决项目中的实际问题的技术都是耍流氓... 一.后台管理系统发送消息 瞎咧咧:后台管理系统发送消息到交换机中,然后通知其 ...

  4. ios摇一摇功能

    在 UIResponder中存在这么一套方法 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_A ...

  5. 亲测可用)html5 file调用手机摄像头

    在切图网一个客户的webapp项目中需要用到 html5调用手机摄像头,找了很多资料,大都是 js调用api  然后怎样怎样,做了几个demo测试发现根本不行, 后来恍然大悟,用html5自带的 in ...

  6. SVN CommandLine

    要是SVN命令行用不了的话: 1.SVN装了没? 2.SVN安装时,选项“command line client tools”选了没. 检出: svn checkout [-depth ARG] [- ...

  7. C语言学习6

    int i; 定义整形变量i int *p;  p为指向整型数据的指针变量 int a[n]: 定义整形数组a,他有n个元素 int *p[n]:   定义指针数组p,它有n个指向整型数据的指针元素组 ...

  8. 02--Activiti初始化表

    初始化数据库 方法一:执行sql脚本文件activiti-5.13\database\create\activiti.mysql.create.*.sql文件 方法二:代码创建(有流程自然就有表) p ...

  9. Quartz --quartz.properties

    quartz.properties 如果项目中没有该配置文件,则会去jar包中读取自带配置文件 默认的配置如下 # Default Properties file for use by StdSche ...

  10. Linux基础命令回顾

    前言 说到linux基础命令,网上一搜一箩筐,想学也有很多教程,如果你不幸看到此篇文章,想看就认真看完,毕竟你点进来了不是嘛? 我每次写的文章都是为了分享自己的学习成果或重要知识点,希望能帮助更多的人 ...