代码之家  ›  专栏  ›  技术社区  ›  petegoast

使用线程更新可变布尔数组

  •  2
  • petegoast  · 技术社区  · 7 年前

    我是一个正在学习并行编程的CS学生,所以我对线程的知识仍然是暂时的。

    我只是有点拘泥于用线程更新共享数组的逻辑。我正在创建一个程序,它允许潜在的无限多线程不断更新一个10大小的布尔数组,以模拟一个座位区的想法,在那里人们可以进去,坐下一段随机的时间,然后离开。这是我的代码:

    class Viewer extends Thread{
        private String name;
        private int index;
        volatile boolean[] seats;
    
    
        Viewer(boolean[] st, String n){
            seats = st;
            name = n;
        }
    
        public void run() {
            ViewingStand vs = new ViewingStand(seats);
            this.index = vs.findSeat(name, seats);
                try {
                    Thread.sleep((long)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                seats = vs.leaveSeat(name, seats, index);
    
        }
    }
    
    class ViewingStand{
        private volatile boolean[] area; //the array used by threads
        private int seatNo; //index of whatever area is being taken or left.
        Random rand = new Random();
        boolean found = false;
    
        public ViewingStand(boolean st[]){
        this.area = st;
        }
    
        public int findSeat(String s, boolean[] seats){
            this.area = seats;
            while(found == false) {
                for(int i=0; i < area.length; i++) {
                    if(area[i] == true) {
                        found = true;
                        this.seatNo = i; 
                        area[seatNo] = false;
                        System.out.println(s + " has found a seat.");
                        return this.seatNo;
                    }
                }
                System.out.println(s + " has started searching again.");
            }
            return -1; //should never reach this
        }
    
        public boolean[] leaveSeat(String s, boolean[] area, int n){
            this.area = area;
            this.area[n] = false;
            System.out.println(s + " has left their seat.");
            return this.area;
        }
    

    这个程序的结果是数组最初填充了10个元素(我从主程序传递的数组的大小),然后这些线程离开“an”数组,但显然不是我在两个视图和方法之间来回传递的数组,因为第10个之后的每个后续线程都会被卡住寻找座位。希望有人能为我指明正确的方向。谢谢您!

    2 回复  |  直到 7 年前
        1
  •  3
  •   Krease    7 年前

    首先,我将忽略并发性问题,然后直截了当地寻找您所询问的逻辑错误。- leaveSeat 正在设置 this.area[n] = false -这似乎表明座位被占了 findSeat 如果该值为 true )。

    在并发性问题上:您的循环检查座位可能有问题-多个线程可以确定一个座位是空的(并进入if块),并且所有“声明”同一个座位。您应该构造的一个实例 ViewingStand 并让它管理对座位的访问-使用类似 synchronized 或者锁定以确保多个线程不会同时修改座位的状态。

        2
  •  1
  •   Stephen C    7 年前

    在并发方面…

    1. A volatile boolean[] 不太可能是线程安全的。这个 volatile 语义只适用于数组引用,而不适用于对数组元素的访问和更新。

    2. 对数组元素执行单独的读写操作。volatile意味着单次读取保证看到即时正确的值,即任何线程的最后一次写入的值。但这并不能阻止种族状况。

      你的代码,一个线程执行一个读取测试,如果一个座位是空闲的,然后执行一个写入来保留它。这个序列不是原子的。没有什么能阻止另一条线在这条线的读写之间“抓住座位”。

    不幸的是,确保代码不存在此类问题的唯一方法是执行 形式分析 (即构造数学声音证明)从Java内存模型的指定语义开始 .这很困难。因此,通常建议使用 java.util.concurrent , java.util.concurrent.atomic java.util.concurrent.locks 包装。


    1-如果您了解JMM,可以接受非正式分析…