《Practical Java》一书“实践51:在单一操作中锁定所有用到的对象”中,有如下代码:
public synchronized int sumArrays(int[] a1, int[] a2)
{
int value = 0;
int size = a1.length;
if (size == a2.length)
{
for (int i=0; i<size; i++)
value += a1[i] + a2[i];
}
return value;
}
{
int value = 0;
int size = a1.length;
if (size == a2.length)
{
for (int i=0; i<size; i++)
value += a1[i] + a2[i];
}
return value;
}
然后指出“这段代码的疏漏在于,尽管函数被声明为synchronized,它所操纵的对象却并非如此。记住,关键字synchronized锁定的是对象,而非函数或代码。因此,当另一个线程改变未被锁之对象(内容)时,sumArrays函数依然可以执行。这种情况下会产生错误”,于是,作者提出对付这种错误的办法:
public int sumArrays(int[] a1, int[] a2)
{
int value = 0;
int size = a1.length;
if (size == a2.length)
{
synchronized(a1) {
synchronized(a2) {
for (int i=0; i<size; i++)
value += a1[i] + a2[i];
}
}
}
return value;
}
{
int value = 0;
int size = a1.length;
if (size == a2.length)
{
synchronized(a1) {
synchronized(a2) {
for (int i=0; i<size; i++)
value += a1[i] + a2[i];
}
}
}
return value;
}
并指出,上面的代码,在循环中的数组不可能被其他线程修改。
我认为这个似乎是不对的,其他线程仍然可以修改数组的元素。不知道是我理解错了作者的意图,还是作者错了?
下面是一个测试程序:
public class Test
{
public static void main(String args[])
{
int a[] = new int[10000];
Sum s = new Sum(a);
Modify m = new Modify(a);
s.start();
m.start();
}
}
class Modify extends Thread
{
int a[];
Modify(int a[])
{
super();
this.a = a;
}
public void run()
{
int len = a.length;
for(int i=0; i<len; ++i)
{
a[i] = 1;
}
}
}
class Sum extends Thread
{
int a[];
Sum(int a[])
{
this.a = a;
}
void delay()
{
int x;
for(int i=0; i<10; ++i)
for(int j=1; j<100; ++j)
x = i / j;
}
int sum(int a[])
{
int len = a.length;
int sum = 0;
synchronized(a)
{
for(int i=0; i<len; ++i)
{
sum += a[i];
delay();
}
}
return sum;
}
public void run()
{
System.out.println(sum(a));
}
}
{
public static void main(String args[])
{
int a[] = new int[10000];
Sum s = new Sum(a);
Modify m = new Modify(a);
s.start();
m.start();
}
}
class Modify extends Thread
{
int a[];
Modify(int a[])
{
super();
this.a = a;
}
public void run()
{
int len = a.length;
for(int i=0; i<len; ++i)
{
a[i] = 1;
}
}
}
class Sum extends Thread
{
int a[];
Sum(int a[])
{
this.a = a;
}
void delay()
{
int x;
for(int i=0; i<10; ++i)
for(int j=1; j<100; ++j)
x = i / j;
}
int sum(int a[])
{
int len = a.length;
int sum = 0;
synchronized(a)
{
for(int i=0; i<len; ++i)
{
sum += a[i];
delay();
}
}
return sum;
}
public void run()
{
System.out.println(sum(a));
}
}
如果按作者说的那样,那么每次运行的时候,打印的值应该是0,事实却并非如此。