这个练习来自Kathy Seirra和Bert Bates的SCJP教材。
同步一个代码块:我们将尝试同步一段代码块。在该代码块中,我们将锁定一个对象,以便在执行代码块时其他线程无法修改它。我们将创建三个线程,它们都会尝试操作同一个对象。每个线程将输出一个字母100次,然后将该字母加1。我们将使用StringBuffer作为对象。
我们可以同步一个String对象,但是一旦创建了字符串,就无法修改它们,因此如果不生成新的String对象,我们将无法增加字母。最终输出应该是连续的100个A,100个B和100个C。
- 创建一个类并扩展Thread类。
- 覆盖Thread的run()方法。这是同步代码块的位置。
- 为了使我们的三个线程对象共享同一个对象,我们需要创建一个构造函数,该构造函数接受一个StringBuffer对象作为参数。
- 同步代码块将从第3步获取StringBuffer对象上的锁。
- 在该块内,将StringBuffer输出100次,然后增加StringBuffer中的字母。您可以查看第6章有关StringBuffer方法的帮助。
- 最后,在main()方法中,使用字母A创建一个StringBuffer对象,然后创建三个我们的类实例并启动它们所有三个。
我已经为上述练习编写了以下类(我将打印10个字符而不是100个)。
class MySyncBlockTest extends Thread {
StringBuffer sb;
MySyncBlockTest(StringBuffer sb) {
this.sb=sb;
}
public static void main (String args[]) {
StringBuffer sb = new StringBuffer("A");
MySyncBlockTest t1 = new MySyncBlockTest(sb);
MySyncBlockTest t2 = new MySyncBlockTest(sb);
MySyncBlockTest t3 = new MySyncBlockTest(sb);
t1.start();
t2.start();
t3.start();
}
public void run() {
synchronized(this) {
for (int i=0; i<10; i++) {
System.out.print(sb);
}
System.out.println("");
if (sb.charAt(0)=='A')
sb.setCharAt(0, 'B');
else
sb.setCharAt(0, 'C');
}
}
}
我原本期待得到如下输出结果(10个A,10个B和10个C),但实际上并没有得到。
AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC
相反,我得到了不同的输出,因为在其他线程完成之前,这三个线程有机会进入循环。
AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC
我的问题是为什么run方法中的同步块没有起作用?