如何在不使用 Java 库中的 CyclicBarrier 的情况下制作我自己的 CyclicBarrier

Posted

技术标签:

【中文标题】如何在不使用 Java 库中的 CyclicBarrier 的情况下制作我自己的 CyclicBarrier【英文标题】:How to make my own CyclicBarrier without use CyclicBarrier from Java Library 【发布时间】:2021-07-09 23:43:44 【问题描述】:

我在大学的 PacMan 游戏中工作,基本上我必须制作自己的 CyclicBarrier,因为我不能使用 Java 中的 CyclicBarrier 库。当幽灵到达特定位置(GhostGoal)时,此屏障将用于保留幽灵,并且他们必须等待更多幽灵,直到我的 CyclicBarrier 的构造函数中给出的最大幽灵。 Ghosts 对象实现可运行(线程)。

我以这种方式构建我的 CyclicBarrier:

public class Barreira 
    private int num_threads;
    private int count;
    
    public Barreira(int num_threads) 
        this.num_threads=num_threads;
    
    
    public synchronized void await() 
        while(count < num_threads) 
            try 
                wait();
             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
        notifyAll();    
    
    
    public synchronized void adiciona() 
        count+=1;
    
    
    public int getNumThreadsNaBarreira() 
        return count;
    
    
    public synchronized void reset() 
        count=0;
    


而我调用屏障的代码(在使用名称 barreira 对其进行初始化之后)以这种方式位于此空白中:

public synchronized void arrivePosition()
...

if((Object)floor[y][x] instanceof GhostGoal && entity instanceof Ghost ) 
            barreira.adiciona();
            barreira.await();
            
        


但是,当一个幽灵到达该位置时,所有幽灵都停止移动,不仅是在该位置的幽灵......基本上一切都冻结了,因为我在名为 barreira 的屏障中等待。

有人可以帮忙吗?

非常感谢。

我也在考虑这个解决方案(删除 await 方法并仅使用 adiciona 方法:

public class Barreira 
    ...
    private List <Ghost> barreiraGhosts = new ArrayList<Ghost>();
    
public synchronized void adiciona(Ghost g)  //teste
    while(contador <num_threads) 
    try 
        contador+=1;
        barreiraGhosts.add(g);
        g.wait();
     catch (InterruptedException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    
    notifyAll();
    for(Ghost b: barreiraGhosts)
        b.run();
    reset();





public synchronized void arrivePosition()
    ...
    
if((Object)floor[y][x] instanceof GhostGoal && entity instanceof Ghost ) 
            barreira.adiciona(entity);
        


什么是最好的解决方案?

【问题讨论】:

1.将 notifyAll() 从 await() 移动到 adiciona() 以通知所有条件已更改 2. 为了正式符合 JMM,防止数据竞争,确保读者看到 getNumThreadsNaBarreira() 的实际计数值,您还必须使 getter 同步,或者将计数定义为 volatile。此外,尽可能使用 final 关键字(对于您的 num_threads)。最终字段使您的意图更加清晰,并且就 JMM docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 而言,它们具有额外且有用的语义(产生冻结动作) 我试过但没用,发生同样的冻结。 【参考方案1】:

嗯...)这是我在评论中所说的:

public class Test 

    public static void main(String[] args) throws Exception 
        final Thread[] threads = new Thread[5];

        final Barreira barreira = new Barreira(threads.length);

        for (int i = 0; i < threads.length; i++) 
            final Thread thread = new Thread(() -> 
                System.out.println("I'm started");
                barreira.adiciona();
                try 
                    barreira.await();
                 catch (InterruptedException e) 
                    Thread.currentThread().interrupt();
                
                System.out.println("I'm finished");
            );
            threads[i] = thread;
        

        for (final Thread thread : threads) 
            thread.start();
        

        for (final Thread thread : threads) 
            thread.join();
        
        System.out.println("All done");
    

    public static class Barreira 
        private final int num_threads;
        private int count;

        public Barreira(int num_threads) 
            this.num_threads = num_threads;
        

        public synchronized void await() throws InterruptedException  // it's a common pattern
            // to declare InterruptedException for possible long/time consuming operations
            while (count < num_threads) 
                wait();
            
        

        public synchronized void adiciona() 
            count += 1;
            notifyAll();
        

        public synchronized int getNumThreadsNaBarreira() 
            return count;
        

        public synchronized void reset() 
            count = 0;
        
    

像魅力一样工作。我认为您在使用屏障时遇到问题,但不是屏障本身...

【讨论】:

以上是关于如何在不使用 Java 库中的 CyclicBarrier 的情况下制作我自己的 CyclicBarrier的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失历史记录的情况下从 SVN 存储库中删除***目录?

Git:如何在不丢失当前分支的情况下克隆项目?

JGit:我可以在不检查的情况下找出某个特定标签是不是存在于 Git 存储库中吗?

java - 如何在spring boot java中编写一个函数来处理JPA存储库中的自定义查询?

如何在不使用临时文件的情况下从 Java 中的嵌套 zip 文件中读取数据?

如何使用 Java 通过 web 服务检索 sharepoint 中文档库中文件的大小