如何同步 2 个异步线程/任务

Posted

技术标签:

【中文标题】如何同步 2 个异步线程/任务【英文标题】:how to synchronise 2 async threads / tasks 【发布时间】:2017-10-06 19:57:08 【问题描述】:

对于我的应用,我必须运行两个操作,都是异步的:

    从文件读取(我使用这个文件来模拟从数据总线读取)-异步操作,因为我不知道“何时”到达新的 总线上的消息/字符。我搜索一个特定的序列 字符,例如帧 start_bytes = "xx" 和随后的 4 个字节是 我等待的“数据”。

    根据从文件中读取的“数据”读取/更新数据到 Firebase - 由于使用 addValueEventListener 导致的异步操作。

我正在考虑一种信号量/互斥体机制或一个简单的布尔标志,即一个任务向另一个任务发出信号,表明必须将新数据保存/更新到 Firebase。

如何同步这两个操作(通过将它们嵌入到任务/AsyncTask/线程中)?

我搜索了这些主题,但发现了与 UI、ProgressBars 等相关的示例 .. 对我的情况不太适合/有用。

在 Firebase 中读取/更新数据

   myRefDevices.addValueEventListener(new ValueEventListener() 
                //  addValueEventListener
                // This method is called once with the initial value and again
                // whenever data at this location is updated.
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) 
                    boolean             bChildFound         = false;
                    DatabaseReference   dbrefChildFound;

                    final CDeviceStatus obj_new = new CDeviceStatus();

                    for( DataSnapshot val : dataSnapshot.getChildren() )
                    
                        if( val.getKey().contentEquals(MAC_ADDRESS[ iIterator ]) )
                        
                            bChildFound = true;

                            dbrefChildFound = val.getRef();

                            obj_new.setiAvailable_A( val.getValue( CDeviceStatus.class ).getiAvailable_A() + 1 );

                            obj_new.setsID(val.getValue( CDeviceStatus.class).getsID() );

                            dbrefChildFound.setValue(obj_new);
                        
                    

                    if(!bChildFound)
                    
                        Log.d("child=" + MAC_ADDRESS[ iIterator ], "not found");
                    


                    if(++iIterator == 16)
                    
                        iIterator = 0;
                    
                

                @Override
                public void onCancelled(DatabaseError databaseError) 

                

            );

从文件中读取:

try 
    // open input stream text file for reading
    Resources res = getResources();
    InputStream instream = res.openRawResource( R.raw.simulated_bus );

    //  we convert it to bufferred input stream
    BufferedInputStream bistreamSimulatedBus = new BufferedInputStream(instream);

        try
            // if we want to stop reading from the file / simulated bus for whatever reason..
            boolean bStayInLoop         = true;

            while ((bistreamSimulatedBus.available() > 0) && bStayInLoop)
            
                try 
                    // throw new InterruptedException();
                    char c = (char) bistreamSimulatedBus.read();

                    if( COUNT_CHARACTERS_NEWLINE )
                    
                        if ( '\n' == c )
                            //  we can count how much NewLine character we have
                            //iNL_Counter++;
                        
                     

                ...

                
                catch ( InterruptedException e ) 
                    throw new RuntimeException( e );
                
            
         catch (IOException e) 
                throw new RuntimeException( e );
         
        finally 
                // release any resource associated with streams
                if ( null != instream ) 
                    instream.close();
                

                if ( null != bistreamSimulatedBus ) 
                    bistreamSimulatedBus.close();
                
            
        
    catch (Exception e) 
        throw new RuntimeException( e );
    

谢谢。

【问题讨论】:

【参考方案1】:

让我们像这样打破解决方案:

基础知识

您有两个操作:o1o2。您希望在第一个操作完成后立即执行第二个操作。

在我看来,显然您需要一个event-driven 解决方案。

接近

利用Publisher/Subscriber设计模式的概念,可以使o1Initiator成为事件的Publisher。然后,当这个特定的操作o1完成后,让类(活动、片段、服务)notify另一个类,我们将称之为Subscriber

代码

将以下行添加到您的build.gradle (app-level)

compile 'org.greenrobot:eventbus:3.0.0'

然后,只需创建一个简单的Plain Old Java Object (POJO) 来代表您的活动。

public class RequestCompletedEvent // add constructor and anything you want

接下来,对于Publish 事件,您只需像这样调用post(POJO instance)

EventBus.getDefault().post(new RequestCompletedEvent(true));

最后,在Subscriber 类中,只需添加以下代码行即可监听通知:

@Override
public void onStart() 
  super.onStart();
  EventBus.getDefault().register(this);


@Override
public void onStop() 
  super.onStop();
  EventBus.getDefault().unregister(this);

然后仍然在同一个类中,使用Subscribe 注释来捕获任何信号:

@Subscribe
public void onEvent(RequestCompletedEvent event) 
   /* Do something */
   //trigger the second operation here;
  startOperationTwo();

总结

这里需要注意的是,最简单的方法是使用async 任务(AsyncTask 子类)来读取您的文件,然后在成功完成后,在onPostExecute() 内,您可以通知@ 987654344@启动下一个操作。

我希望这会有所帮助;还有祝你好运!如果您需要进一步的帮助,请告诉我!

【讨论】:

以上是关于如何同步 2 个异步线程/任务的主要内容,如果未能解决你的问题,请参考以下文章

如何在同一线程上调度异步以进行串行处理

同步异步 + 回调函数

同步/异步 异步回调 协成 线程队列

GCD的小结

python网络编程04 异步与同步编程事件驱动

iOS面试系列-2多线程中同步异步和串行并行之间的逻辑关系(必考,必须掌握)