Java 随机终止的可重入锁定线程
我一直在做一个关于Java多线程的学校作业。我一直坚持的一个任务是,我们需要在不同的组中创建多个线程,一旦每个组中有4个线程,只有这样它们才能被释放以协同工作,否则它们必须被搁置/等待。例如: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,它被挂上等待 这是我完成的一般任务。我正在处理的任务要求我们释放组中最初的
- 线程a、b、c加入组7,它们都处于等待状态
- 线程d加入组7,所有四个线程(a、b、c、d)都会收到终止的信号
- 线程e,f,g,h,i加入组8,在这种情况下,当线程i处于等待状态时,e,f,g,h将收到终止的信号
- 线程j加入组7,它被挂上等待
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),您不向其他线程发送信号,但在到达其中四个线程时仍然终止它们。这就是发生的情况:
以下是实现这一点的潜在方法:
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()方法。只有这样他们才应该执行,否则他们应该继续等待。这是一个复杂的要求。我的程序中也有类似的复杂要求。我在回答中描述了解决这个问题的方法,希望这能帮助您实现逻辑。这很有意义!非常感谢你。我知道怎么做了。