Java 使用线程更新易失性布尔数组
我是一名计算机科学专业的学生,目前正在学习并发编程,所以我对线程的知识仍然是,呃,初步的 我只是对用线程更新共享数组的逻辑有点困惑。我正在创建一个程序,它允许潜在的无限多个线程不断更新一个大小为10的布尔数组,以模拟一个座位区的想法,人们可以进去,坐一段随机的时间,然后离开。这是我的密码:Java 使用线程更新易失性布尔数组,java,arrays,multithreading,concurrency,Java,Arrays,Multithreading,Concurrency,我是一名计算机科学专业的学生,目前正在学习并发编程,所以我对线程的知识仍然是,呃,初步的 我只是对用线程更新共享数组的逻辑有点困惑。我正在创建一个程序,它允许潜在的无限多个线程不断更新一个大小为10的布尔数组,以模拟一个座位区的想法,人们可以进去,坐一段随机的时间,然后离开。这是我的密码: class Viewer extends Thread{ private String name; private int index; volatile boolean[] seat
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;
}
类查看器扩展线程{
私有字符串名称;
私有整数索引;
[]个席位;
查看器(布尔值[]st,字符串n){
座位=st;
name=n;
}
公开募捐{
观景台vs=新观景台(座椅);
this.index=vs.findSeat(姓名、座位);
试一试{
sleep((long)(Math.random()*1000));
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
席位=vs.leaveSeat(名称、席位、索引);
}
}
类视图标准{
private volatile boolean[]区域;//线程使用的数组
private int seatNo;//获取或留下的任何区域的索引。
Random rand=新的Random();
布尔值=false;
公共视图标准(布尔值st[]){
该面积=st;
}
public int findSeat(字符串s,布尔[]座位){
这个区域=座位;
while(find==false){
对于(int i=0;i
这个程序的结果是数组最初被10个元素填充(我从主程序传递的数组的大小),这些线程然后会留下“an”数组,但显然不是我在两个viewinstand方法之间来回传递的同一个数组,因为在第10个之后的每个后续线程都会被困在寻找座位的过程中。希望有一些输入能为我指明正确的方向。谢谢!我将首先忽略并发性问题,然后直接查看所看到的内容ms就像您询问的逻辑错误一样-
leaveSeat
正在设置此。区域[n]=false
-这似乎表明座位已被占用(如果值为true
,则您的findSeat
方法假定座位为空)
关于并发性问题:您的循环检查席位时可能会遇到问题-多个线程可能会确定一个席位为空(并进入if块),以及所有“声明”同一个席位。您应该构造一个
ViewingStand
实例,并让它管理对席位的访问-使用并发控制,如synchronized
或锁定,以确保多个线程不会同时修改席位的状态。在并发端
volatile boolean[]
不太可能是线程安全的。volatile
语义仅适用于数组引用,而不适用于对数组元素的访问和更新Java.util.concurrent
、Java.util.concurrent.atomic
和Java.util.concurrent.locks
包提供的标准构建块
1-如果您了解JMM,可以首先对代码样式进行非正式分析。允许查看者对数组进行原始访问。这违反了OO设计的原则。布尔数组应该由
查看标准
封装,仅由其方法处理
重写后,代码看起来会更好,但由于并发性问题,仍然是错误的
对实际数据的访问,
boolean[]
的内容不是易变的。使用关键字的方式只会使对数据的引用变为易变的。由于引用根本没有改变,添加的volatile
除了可能使访问变慢之外,没有任何作用
即使您成功地对数组的内容进行了易失性读写,仍然存在并发性问题,因为检查空闲座位并占用它不是原子的
使访问原子化的一种方法是添加锁(使方法同步化
),从本质上说,强制对ViewingStand
的访问一个接一个地进行。通过锁强制执行的“发生在之前”顺序,您甚至不需要volatile
但是,如果将锁添加到findSeat
,则第n+1个查看器将保持锁,并继续查找空的