同步一段代码 - 练习13-2

时间:2017-06-07 18:06:31

标签: java multithreading synchronization

在本练习中,我们将尝试同步一段代码。在该代码块中,我们将获得对象的锁定,以便其他线程在代码块执行时无法修改它。我们将创建三个线程,它们都将尝试操作同一个对象。每个线程将输出一个单个字母100次,然后将该字母递增1。我们将使用的对象是StringBuffer。我们可以在String对象上进行同步,但是一旦创建了字符串就无法修改它们,因此我们无法在不生成新String对象的情况下增加字母。最终输出应该有100 A,100 B和100 C,所有都是不间断的。

  1. 创建一个类并扩展Thread类。

  2. 覆盖Thread的run()方法。这是同步代码块的用武之地。

  3. 为了让我们的三个线程对象共享同一个对象,我们需要创建一个在参数中接受StringBuffer对象的构造函数。

  4. 同步的代码块将从步骤3获取StringBuffer对象的锁定。

  5. 在块中,输出StringBuffer 100次,然后在StringBuffer中递增字母。您可以在第5章中查看有助于此的StringBuffer(StringBuilder)方法。

  6. 最后,在main()方法中,使用字母A创建一个StringBuffer对象,然后创建我们类的三个实例并启动它们中的所有三个。

  7. 解决方案:

    公共类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 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 线程2 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 线程1 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

    问题:如果我使用Stringbuilder或StringBuffer,则无关紧要,因为我使用的是同步块。

    但是如果我使用synchronized(this)而不是stringbuffer对象。输出是不可预测的。由于字符串缓冲区已经同步,为什么我们需要自己做呢?

2 个答案:

答案 0 :(得分:1)

您将相同的引用传递给所有三个线程。如果他们同步,那么他们都可以同时写入StringBuffer。如果它们在公共StringBuffer上同步,则一次只能有一个线程访问它。

答案 1 :(得分:0)

StringBuffer已同步,但仅适用于每个单独的方法调用。这意味着当您不使用同步时,打印字符串缓冲区值的部分不会在同步块中完成。其中一个线程可以在此期间更新缓冲区。发生这种情况时,打印件将显示新值。您无法真正知道哪个线程会首先更新缓冲区。

此外,线程可能会更改对sb.charAt()的调用与sb.setCharAt()的调用之间的值。因此增量本身的结果可能是不可预测的。

注意:在this上进行同步意味着每个线程正在同一个锁上进行同步,因此它根本就不会同步。