当前位置: 首页 > 知识库问答 >
问题:

条件任务调度-多线程Java应用程序

傅高逸
2023-03-14

我有一个包含“资源管理器”类的多线程Java应用程序。

此类提供了一个资源列表,这些资源可以作为初始化参数请求。然后检查每个文件的本地文件系统,并将确定为本地的文件添加到列表中。

当类收到资源请求时,会发生以下情况之一:

>

  • 如果资源被确定为本地资源(在列表中):请提供可以找到它的URI。

    如果资源是远程的(不在列表中):安排一个工作进程来获取资源。工作进程将在任务完成时通知经理,并更新本地资源列表。(请求线程不等待-它在那里或不在那里)。

    由于多个线程可以请求资源,ReadWriteLock用于协调列表访问。许多线程可以同时读取列表,当需要更新时,将使用写回。

    问题是为任何特定的远程资源调度后台工作人员。如果多个线程为同一资源调度工作人员,则需要不必要的开销(即使重复任务不会完全执行,因为它们会检查这种情况)。为了实现尽可能高的效率,我想知道以下实现:

    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    
    //assume each resource object has a volatile boolean "scheduled"
    //with isScheduled() and setSheduled() setter/getter;
    
    //assume the resource list is thread safe
    
    public URI requestResource(Resource theResource){
      URI resourceId = null;
      //many threads can enter here 
      lock.readLock().lock();
      try{
        //if our resource is not in the list
        if(!localResouces.contains(theResource)){
           //double-check idiom...does it work here?
           //if the resource isn't scheduled
           if(!theResource.isScheduled()){
              //only one thread may enter here
              synchronized(this){
                if(!theResource.isScheduled()){
                   //schedule task here...
                   theResource.setScheduled(true);                                      
                }
              }  
           }
        } else {
           //its local, return the location
           resouceId = theResource.getURI();
        }
      } finally {
        lock.readLock().unlock();
      }
    //requesting object will deal with null value;
    return resouceId;
    }
    

    当工人完成时:

    public void update(Resource theResource){
      //ensures no threads in the read block
      lock.writeLock().lock();
      try {
          //update the list (would check result IRL, and not add if problem found)
          localResources.add(theResource);
          //set the scheduled field
          theResource.setScheduled(false); 
      } finally {
           lock.writeLock().unlock();
      }
    }
    

    同样,我想最大限度地提高效率。我找不到与这种情况相匹配的示例——即允许常见操作的高吞吐量,同时允许以最小的阻塞/开销调度任务。

    这种方法有什么问题?第一个方法必须同时获得读锁和同步,但是更新方法只需要获得写锁,因为isScheduled的检查封装在读块中。这是否提供线程安全的调度和数据访问?

    编辑:

    我测试了上述方法,我看到了正确的行为。我仍然不确定这是否真的是“线程安全的”

  • 共有1个答案

    牧献
    2023-03-14

    我可能会这样做:

    class Resource
    
        Uri localUri;
        volatile int state; // REMOTE, FETCHING, LOCAL
    
        Resource()
            if local
                localUri = ...;
                state = LOCAL;
            else
                state = REMOTE
    
        URI requestResource()
    
            if(state==LOCAL)  // volatile read
                return localUri;
            if(state==FETCHING)
                return null;
    
            synchronized(lock)
                if(state==LOCAL)
                    return localUri;
                if(state==FETCHING)
                    return null;
    
                // REMOTE, and it's my job to initiate fetching
                state=FETCHING;
                // do actaul fetching outside synchronized block
    
            schedule fetching...
    
        void onFetchingDone()
    
            synchronized(lock)
    
                if error
                    state=REMOTE; // to retry.
                    // if we consider error unrecoverable,
                    // we need an ERROR state.
                else
                    ...
                    loalUri = ...;
                    state = LOCAL;  // volatile write
    
     类似资料:
    • 多任务是一个操作系统可以同时执行多个程序的能力。基本上,操作系统使用一个硬件时钟为同时执行的每个程序配置「时间片段」。如果时间片段够小,并且机器也没有由于太多的程序而超出负荷时,那么在使用者看来,所有的这些程序似乎在同时执行着。 多任务并不是什么新的东西。在大型计算机上,多任务是必然的。这些大型主机通常有几十甚至几百个终端机和它连结,而每个终端机使用者都应该感觉到他或者她独占了整个计算机。另外,大

    • 主要内容:1 Java 线程调度程序,2 抢占式调度与时间片调度的区别1 Java 线程调度程序 Java中的线程调度程序是JVM(Java虚拟机)的一部分,它决定应该运行哪个线程。 我们无法保证线程调度程序将会选择哪个线程来运行。 一次只能在一个进程中运行一个线程。线程调度程序主要使用抢占式或时间片调度来调度线程。 2 抢占式调度与时间片调度的区别 在抢占式调度下,最高优先级的任务会一直执行,直到进入等待状态或死机状态或存在更高优先级的任务为止。 在时间分片调度下

    • 我有一个MainClass,一个Worker类和一个Supervisor类。在MainClass中,我创建了10个Worker类和一个Supervisor类,它们在不同的线程中运行。 . . 我不知道如何实现这个,因为每个线程中的条件是相互独立的,所以我不需要同步,所以我不能使用等待通知。

    • 主要内容:1 如何使用多个线程执行一个任务,2 如何使用多个线程执行多个任务1 如何使用多个线程执行一个任务 如果需要由多个线程执行单个任务,则只有一个run()方法,例如: 1.1 多个线程执行一个任务示例1 输出结果为: 1.2 多个线程执行一个任务示例2 输出结果为: 注意:每个线程在单独的堆栈中运行。 2 如何使用多个线程执行多个任务 如果必须通过多个线程执行多个任务,请使用多个run() 方法: 2.1 多个线程执行多个任务示例1 输出结果为: 2.2 多个线程

    • 我使用Timer和TimerTask为聊天应用程序长轮询新消息。我想研究两种“稍微”不同的可能性: 1:计时器声明为局部变量 *问题:每次调用该方法时,我都会看到创建了一个新线程,[Timer-1]、[Timer-2]等等。。在Eclipse调试窗口中,即使在getLastMessages(..)之后,它们似乎都在运行完成运行并向客户端返回值。如果计时器实际使用线程,并且在几次事务之后,服务器最终