我有一个类Repository
,它分配表示为cells
数组字段值的资源。该方法将资源从一个单元移动到另一个单元。
我需要确保当我们将资源从一个单元格移动到另一个单元格时,不能对所讨论的单元格执行其他移动操作。也就是说,如果一个单元(原始单元或目标单元)参与move
操作,我们必须等到当前操作完成后再对这些单元执行另一个move
操作。对不同的单元格对并行执行move
应该没有限制,例如,move(cells[1], cells[2], 5)
和move(cells[4], cells[7], 9)
可以并行执行。
我想使用两个嵌套的synchronized
块来保护原始和目标单元格。我认为我们不需要使用wait
/ notifyAll
,因为我们仍在使用synchronized
。
我是在正确的轨道上吗?
这是代码(moveOriginal
是原始方法,moveSynchronized
是受保护的方法:
public class Repository {
private Integer[] cells;
public Repository(int size, int initialValue) {
cells = new Integer[size];
for(int i = 0; i < size; i++) {
cells[i] = initialValue;
}
}
public void moveOriginal(int from, int to, int amount) {
if(cells[from] >= amount) {
cells[from] = cells[from] - amount;
cells[to] = cells[to] + amount;
}
}
public void moveSynchronized(int from, int to, int amount) {
synchronized(cells[from]) {
synchronized (cells[to]) {
if(cells[from] >= amount) {
cells[from] = cells[from] - amount;
cells[to] = cells[to] + amount;
}
}
}
}
}
答案 0 :(得分:3)
这种方法存在多个问题。
$args = array(
'post_type' => 'course',
'post_status' => 'publish'
);
if(!empty($cs_course_cate)){
$args = array('tax_query' => array(
array(
'taxonomy' => 'course-category',
'terms' => $cs_course_cate,
'field' => 'term_id',
)
));
}
if(!empty($cs_campus)){
$args = array('meta_query' => array(
array(
'key' => 'cs_course_campus_id',
'value' => $cs_campus,
'compare' => 'LIKE',
),
)
);
}
锁定了synchronized
的值cell[x]
,所以只要你这样做
Integer
cells[from] = cells[from] - amount;
上的同步会锁定另一个对象。
cells[from]
实习对象代表小值。锁定这样的共享对象可能会将您锁定在完全错误的单元格之外。
Integer
个对象的可用性超出了您的主题。另一个线程可以获取您同步的共享整数,并锁定Integer
,而无法访问您班级的私有数据结构。如果要进行单元级锁定,请创建一个专门用于锁定相应单元格的对象数组;不要锁定单元格值。
答案 1 :(得分:2)
不,你不能这样做。为此,您需要锁定阵列本身,以防止并行操作。
cells
是不可变的,意味着Integer
会在其中放置不同的对象,而不是修改其中的cells[to] = cells[to] + amount
。当Integer
在不同时间引用不同的对象时,这将导致问题。
解决此问题的最简单方法是使用synchronized(cells[to])
初始化Object[] lockArray = new Object[size];
并对其进行同步。它们不会在您的业务逻辑中发生变化。
在任何情况下,您都需要嵌套的Objects
范围。您还需要做的是define an order,例如始终首先在较小的值上同步。否则,当多个线程同时尝试执行synchronized
之类的操作时,您将遇到死锁。
move(1, 2); move(2, 1);