在本练习中,我们将尝试同步一个代码块。在该代码块中,我们将获得对象的锁,以便其他线程在执行代码块时无法修改它。我们将创建三个线程,它们都将尝试操作同一个对象。每个线程将输出一个字母100次,然后将该字母增加一个。我们将要使用的对象是StringBuffer。我们可以对String对象进行同步,但是一旦创建字符串,就不能修改字符串,因此,如果不生成新的String对象,就无法增加字母。最终的输出应该有100 A,100 B和100 C,所有的线都是不间断的。
解决方案:
公共类OCJPThread扩展线程{
StringBuffer sb;
public OCJPThread(StringBuffer sb) {
this.sb =sb;
}
public void run(){
synchronized (sb) {
System.out.println(Thread.currentThread().getName());
for(int i=1;i<=100;i++)
System.out.print(sb);
System.out.println();
sb.setCharAt(0, (char)(sb.charAt(0)+1));
}
}
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("A");
OCJPThread t1 =new OCJPThread(sb);
OCJPThread t2 =new OCJPThread(sb);
OCJPThread t3 =new OCJPThread(sb);
t1.start();
t2.start();
t3.start();
}}输出线程-0线程-2线程-1
问:如果我使用的是Stringbuilder或StringBuffer,这并不重要,因为我使用的是同步块。
但是如果我使用同步(这个)而不是字符串缓冲区对象。输出是不可预测的。既然字符串缓冲区已经被同步,为什么我们需要自己来做呢?
发布于 2017-06-07 18:18:21
StringBuffer是同步的,但只对每个单独的方法调用进行同步。这意味着当您不使用同步时,打印字符串缓冲区值的部分不会在同步块中完成。在此期间,其他线程之一可以更新缓冲区。当这种情况发生时,打印将显示新值。您不能真正知道哪个线程会首先更新缓冲区。
另外,线程可以更改对sb.charAt()的调用和对sb.setCharAt()的调用之间的值。因此,增量本身的结果可能是不可预测的。
注意:this上的同步意味着每个线程在不同的锁上同步,所以它就像根本不同步一样。
发布于 2017-06-07 18:08:20
您正在传递对所有三个线程的相同引用。如果它们在这方面同步,那么它们都可以同时写入StringBuffer。如果它们在公共StringBuffer上同步,那么一次只能访问一个线程。
https://stackoverflow.com/questions/44419852
复制相似问题