Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 随机终止的可重入锁定线程_Java_Multithreading_Reentrantlock_Extrinsic Parameters - Fatal编程技术网

Java 随机终止的可重入锁定线程

Java 随机终止的可重入锁定线程,java,multithreading,reentrantlock,extrinsic-parameters,Java,Multithreading,Reentrantlock,Extrinsic Parameters,我一直在做一个关于Java多线程的学校作业。我一直坚持的一个任务是,我们需要在不同的组中创建多个线程,一旦每个组中有4个线程,只有这样它们才能被释放以协同工作,否则它们必须被搁置/等待。例如: 线程a、b、c加入组7,它们都处于等待状态 线程d加入组7,所有四个线程(a、b、c、d)都会收到终止的信号 线程e,f,g,h,i加入组8,在这种情况下,当线程i处于等待状态时,e,f,g,h将收到终止的信号 线程j加入组7,它被挂上等待 这是我完成的一般任务。我正在处理的任务要求我们释放组中最初的

我一直在做一个关于Java多线程的学校作业。我一直坚持的一个任务是,我们需要在不同的组中创建多个线程,一旦每个组中有4个线程,只有这样它们才能被释放以协同工作,否则它们必须被搁置/等待。例如:

  • 线程a、b、c加入组7,它们都处于等待状态
  • 线程d加入组7,所有四个线程(a、b、c、d)都会收到终止的信号
  • 线程e,f,g,h,i加入组8,在这种情况下,当线程i处于等待状态时,e,f,g,h将收到终止的信号
  • 线程j加入组7,它被挂上等待
这是我完成的一般任务。我正在处理的任务要求我们释放组中最初的4个线程,其余线程应该等到前面的4个线程调用finished()

例如,3个线程加入组65,它们被置于等待状态。另一个线程连接组65,所有4个线程一起释放。现在有4个线程正在工作(终止)。现在线程e,f,g,h,i,j,k,l加入65组。所有这些函数都要等待e、f、g、h调用finished()方法

以下是我迄今为止所做的工作:

ExtrinsicSync.java:

import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;

public class ExtrinsicSync {

    private HashMap<Integer, ConditionWrapper> groupThreadCount;
    private ReentrantLock monitor;
    private int count = 0;

    ExtrinsicSync() {
        groupThreadCount = new HashMap<>();
        monitor = new ReentrantLock();
    }

@Override
public void waitForThreadsInGroup(int groupId) {
    monitor.lock();

    if (!groupThreadCount.containsKey(groupId))
        groupThreadCount.put(groupId, new ConditionWrapper(monitor.newCondition()));

    ConditionWrapper condWrapper = groupThreadCount.get(groupId);
    condWrapper.setValue(condWrapper.getValue() + 1);

    if(condWrapper.getValue() == 4 && condWrapper.getInitialStatus())
    {
        condWrapper.getCondition().signalAll();
        condWrapper.setInitialStatus(false);

        System.out.println("Terminating group: " + groupId + "FROM INITIAL STATE: " + ++count);
    } else {
        System.out.println("Putting thread from group: " + groupId + " on wait: " + ++waitcount);
        try { condWrapper.getCondition().await(); }
        catch (InterruptedException e) { e.printStackTrace(); }

    }

    monitor.unlock();
}

@Override
public void finished(int groupId) {
    monitor.lock();
    ConditionWrapper condWrapper = groupThreadCount.get(groupId);

    if(!condWrapper.getInitialStatus())
    {
        condWrapper.setFinishedCount(condWrapper.getFinishedCount() + 1);
        System.out.println("Group: " + groupId + "FINISHED COUNT: " + condWrapper.getFinishedCount());
        if(condWrapper.getFinishedCount() == 4)
        {
            condWrapper.setFinishedCount(0);
            condWrapper.getCondition().signalAll();
            System.out.println("Terminating threads for group: " + groupId + ": " + ++count);
        }
    }
    monitor.unlock();
}
import org.junit.Test;

import java.util.EnumMap;

class TestTask1 implements Runnable{

    final int group;
    final ExtrinsicSync s1;

    TestTask1(int group, ExtrinsicSync s1)
    {
        this.group = group;
        this.s1 = s1;
    }

    public void run() { s1.waitForThreadsInGroup(group); s1.finished(group); }
}

public class ExtrinsicSyncTest {

    @Test
    public void testPhaseThreethreads() {

        int nThreads = 22;

        Thread t[] = new Thread[nThreads];
        final ExtrinsicSync s1 = new ExtrinsicSync();

        for(int i = 0; i < nThreads/2; i++)
            (t[i] = new Thread(new TestTask1(66, s1))).start();

        for(int i = nThreads/2; i < nThreads; i++)
            (t[i] = new Thread(new TestTask1(70, s1))).start();

        for (Thread ti : t)
        {
            try { ti.join(100); }
            catch (Exception e) { System.out.println(e); }
        }

        EnumMap<Thread.State, Integer> threadsInThisState = new EnumMap<>(Thread.State.class);

        for (Thread.State s : Thread.State.values())
            threadsInThisState.put(s, 0);

        for (Thread ti : t)
        {
            Thread.State state = ti.getState();
            int n = threadsInThisState.get(state);
            threadsInThisState.put(state, n + 1);
        }

        System.out.println("threadsInThisState: " + threadsInThisState.toString() );

    }
}
import java.util.concurrent.locks.Condition;

public class ConditionWrapper {
    private Condition cond;
    private Integer value;
    private Integer finishedCount;
    private boolean initialThreads;

    public ConditionWrapper(Condition condition)
    {
        this.cond = condition;
        this.value = 0;
        this.finishedCount = 0;
        this.initialThreads = true;
    }
    // Returns the condition object of current request
    public Condition getCondition()
    {
        return this.cond;
    }
    // Gets the current counter of threads waiting in this queue.
    public Integer getValue()
    {
        return this.value;
    }
    // Sets the given value. Used for resetting the counter.
    public void setValue(int value) { this.value = value; }
    // Sets the counter to help keep track of threads which called finished() method
    public void setFinishedCount(int count) { this.finishedCount = count; }
    // Gets the finished count.
    public Integer getFinishedCount() { return this.finishedCount; }
    // This flag is to identify initial threads of a group
    public boolean getInitialStatus() { return initialThreads; }
    public void setInitialStatus(boolean val) { this.initialThreads = val; }
}
我遇到的问题是,我能够释放每个组的前四个线程,但不知何故,在某个地方有两个线程被随机终止,我无法弄清楚发生了什么。例如,上面的22个线程测试用例分为两个组,只有8个线程应该被终止,而其余的线程则等待


但是这里有10个线程被终止。我不明白发生了什么事。我已经尽可能地将代码精简到最低限度。

问题是,对于非初始线程(getInitialStatus==false),您不向其他线程发送信号,但在到达其中四个线程时仍然终止它们。这就是发生的情况:

  • 前三个线程增加计数并等待
  • 第四个线程达到count==4并设置initial=false,向所有其他线程发送信号并将计数设置为零
  • 接下来的三个线程将计数增加一
  • 这8个线程达到count==4并被终止。由于getInitialStatus==false,此线程不会通知其他线程
  • 因此,4*2个线程+2个线程被终止。正是你在测试中看到的计数


    以下是实现这一点的潜在方法:

  • 在每个线程或任务中使用标记canExecute
  • 使用calculateState方法计算当前状态,如果允许执行线程,则将标志设置为true
  • 将所有正在等待的线程存储在列表或类似的内容中
  • 因此,您的任务如下所示:

    Task
      boolean canExeute
    
    waitForThreadsInGroup
      monitor.lock();
          add task to list
          calculateTaskState
          condition.notifyAll
          while( ! task.canExcecute )
          {
            condition.await.
          }
    
      monitor.unlock();
    
    waitForThreadsInGroup方法的外观如下:

    Task
      boolean canExeute
    
    waitForThreadsInGroup
      monitor.lock();
          add task to list
          calculateTaskState
          condition.notifyAll
          while( ! task.canExcecute )
          {
            condition.await.
          }
    
      monitor.unlock();
    
    finish方法看起来类似:

      finish
        monitor.lock();
        decrement finish count
        calculateTaskState
       condition.notifyAll
       monitor.unlock();
    
    和计算状态

    calculateTaskState
      if( finishCount == 0)
      {
          if( taskList.size >= 4  )
          {
             set 4 tasks in this list to can execute and remove them from the list
          }
      }
    
    因此,诀窍是将逻辑分为三个步骤:

  • 操作,例如减少完成计数
  • 新状态的计算。并决定是否允许每个线程执行
  • 还有线程的等待。每个线程都需要等待自己的标志

  • 谢谢你的回复,我很抱歉因为生病而延迟回复。虽然你的解决方案肯定是我的问题,但我昨天用不同的方法解决了它。我仍然会奖励奖金和回答,但如果你能看看我的更新代码,看看你是否能发现它的问题,我将不胜感激。基本上,在finished()方法中,程序结束后,最后剩余的线程将被随机终止。我尝试了所有不同的方法,但没有一种适合我。我认为你应该取消初始状态。您想要实现的是,如果每个组有4个线程在运行,那么它们应该执行。之后,如果有4个线程再次运行,它们应该再次执行。因此,如果您只是删除初始逻辑,那么一切都应该很好。因此,基本上按照您已经做的那样计算每个组的线程数。如果ciount小于4,请稍候。如果计数等于4,则将计数设置为零并向所有线程发送信号。实际上不是。只应执行初始的4个线程。该组中的其余线程应等待前面4个线程调用finish()方法。只有这样他们才应该执行,否则他们应该继续等待。这是一个复杂的要求。我的程序中也有类似的复杂要求。我在回答中描述了解决这个问题的方法,希望这能帮助您实现逻辑。这很有意义!非常感谢你。我知道怎么做了。