我试图在许多线程上编写生命游戏,1个单元格= 1个线程,它需要线程之间的同步,因此在其他线程未完成读取先前状态之前,没有线程将开始计算新状态。这是我的代码
public class Cell extends Processor{
private static int count = 0;
private static Semaphore waitForAll = new Semaphore(0);
private static Semaphore waiter = new Semaphore(0);
private IntField isDead;
public Cell(int n)
{
super(n);
count ++;
}
public void initialize()
{
this.algorithmName = Cell.class.getSimpleName();
isDead = new IntField(0);
this.addField(isDead, "state");
}
public synchronized void step()
{
int size = neighbours.size();
IntField[] states = new IntField[size];
int readElementValue = 0;
IntField readElement;
sendAll(new IntField(isDead.getDist()));
Cell.waitForAll.release();
//here wait untill all other threads finish reading
while (Cell.waitForAll.availablePermits() != Cell.count) {
}
//here release semaphore neader lower
Cell.waiter.release();
for (int i = 0; i < neighbours.size(); i++) {
readElement = (IntField) reciveMessage(neighbours.get(i));
states[i] = (IntField) reciveMessage(neighbours.get(i));
}
int alive = 0;
int dead = 0;
for(IntField ii: states)
{
if(ii.getDist() == 1)
alive++;
else
dead++;
}
if(isDead.getDist() == 0)
{
if(alive == 3)
isDead.setValue(1);
else
;
}
else
{
if(alive == 3 || alive == 2)
;
else
isDead.setValue(0);
}
try {
while(Cell.waiter.availablePermits() != Cell.count)
{
;
//if every thread finished reading we can acquire this semaphore
}
Cell.waitForAll.acquire();
while(Cell.waitForAll.availablePermits() != 0)
;
//here we make sure every thread ends step in same moment
Cell.waiter.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
处理器
class extends thread
和run方法如果我打开它调用step()
方法。好吧它适用于少量细胞但是当我运行36个细胞时它开始变得非常慢,如何修复我的同步以便它更快?
答案 0 :(得分:1)
使用大量的线程往往不是非常有效,但36并不是那么多,我希望它本身会产生一个你将其描述为“非常慢”的差异。我认为问题更可能是你的战略所固有的。特别是,我怀疑这种忙碌等待是有问题的:
Cell.waitForAll.release();
//here wait untill all other threads finish reading
while (Cell.waitForAll.availablePermits() != Cell.count) {
}
忙碌等待总是性能问题,因为你正在通过一遍又一遍地测试条件来占用CPU。这种忙等待比大多数都要糟糕,因为它涉及测试同步对象的状态,这不仅会产生额外的开销,还会在线程之间引入额外的干扰。
您希望使用各种方法之一来使线程暂停执行,直到满足条件,而不是忙等待。看起来你实际做的是创建了一个穷人的CyclicBarrier
版本,所以你可以考虑使用CyclicBarrier
本身。或者,由于这是一个学习练习,您可以从学习如何使用Object.wait()
,Object.notify()
和Object.notifyAll()
- Java的内置条件变量实现中受益。
如果你坚持使用信号量,那么我认为你可以在没有繁忙等待的情况下做到这一点。使用信号量的关键是它能够获取指示线程可以继续的信号量(根本),而不是可用许可证的数量。如果你维护一个单独的变量来跟踪给定信号量在给定点上等待多少线程,那么到达该点的每个线程可以确定是否释放所有其他线程(并自行继续)或是否通过尝试阻止获得信号量。