这里每一次线程抢占到CPU都运行run()方法,run方法new了一个ArrayList对象,按道理说每一次新new一个对象都会在堆里面新建一个,为什么到最后这些值都加到了同一个ArrayList对象啊。
public void run() {
ArrayList<Integer> boxList = new ArrayList<>();
//1.循环
//2.同步代码块
//3.判断(共享数据到末尾)
//4.判断(共享数据没有到末尾)
while(true){
synchronized (Thread.class){
Collections.shuffle(list);
int prize = list.remove(0);
boxList.add(prize);
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
并不是每次线程抢占到CPU都从run()方法的第一行开始执行的,而是从哪里停止接着往下执行。
例如这里Thread.sleep(500)让出CPU的执行权,等到下一次调度获得CPU后就从Thread.sleep(500)的下一行开始执行,即while语句,所以从始至终就只new了一个ArrayList对象。
你的代码每个线程在运行run()方法时都会创建一个新的ArrayList对象,并将prize值添加到该对象中。然而,所有线程都使用了同一个list对象,这可能导致混乱的结果。
这是因为synchronized关键字锁定的是类对象 Thread.class,而不是每个线程的实例对象。因此,所有线程都在同一个锁上同步,并且在竞争获得锁的过程中,只有一个线程能够进入同步代码块执行操作。这意味着多个线程会按顺序依次执行同步代码块中的内容。
在这种情况下,多个线程会依次获取锁并执行Collections.shuffle(list)、int prize = list.remove(0)和boxList.add(prize)这些操作,导致所有线程将结果添加到同一个boxList对象中。这解释了为什么所有值都会添加到同一个ArrayList对象中。
如果想要每个线程都拥有独立的ArrayList对象,可以将ArrayList boxList定义为实例变量,而不是在run()方法内部创建。这样,每个线程都会拥有自己的boxList对象,避免多个线程共享同一个对象的问题。