【问题标题】:Synchronized block not working同步块不工作
【发布时间】:2013-08-04 11:31:08
【问题描述】:

这个练习直接来自 Kathy Seirra 和 Bert Bates 的 SCJP

同步代码块

在本练习中,我们将尝试同步一段代码。在该代码块中,我们将获得一个对象的锁,以便其他线程在代码块执行时无法修改它。我们将创建三个线程,它们都将尝试操作同一个对象。每个线程将输出一个字母 100 次,然后将该字母加一。我们将使用的对象是 StringBuffer。

我们可以在 String 对象上进行同步,但字符串不能修改一次 它们是被创建的,所以如果不生成新的 String 对象,我们将无法增加字母。最终的输出应该有 100 个 As、100 个 Bs 和 100 个 Cs,全部用不间断的行。

  1. 创建一个类并扩展 Thread 类。
  2. 重写 Thread 的 run() 方法。这是同步的地方 代码块会消失。
  3. 为了让我们的三个线程对象共享同一个对象,我们需要创建 在参数中接受 StringBuffer 对象的构造函数。
  4. 同步的代码块将获得对 StringBuffer 的锁定 步骤 3 中的对象。
  5. 在块内,输出StringBuffer 100次,然后递增 StringBuffer 中的字母。您可以查看第 6 章的 StringBuffer 有助于解决此问题的方法。
  6. 最后,在 main() 方法中,使用 字母 A,然后创建我们类的三个实例并启动所有三个实例。

我为上述练习编写了下面的课程(而不是 100 我打印了 10 个字符)

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 个 As、10 个 Bs 和 10 个 Cs),但没有得到。

AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC

相反,我得到了如下不同的输出,因为三个线程是 有机会在另一个完成之前进入循环。

AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC

我的问题是为什么run方法中的同步块不起作用?

【问题讨论】:

  • 请问,谁降级,发布说明,为什么
  • 为什么我得到-1?这是一个真正的问题!
  • 可以使用StringBuilder时请不要使用StringBuffer。近 10 年来,StringBuffer 一直是一个遗留类。
  • 谢谢彼得,我知道,我只是想跟着练习。

标签: java multithreading synchronized-block


【解决方案1】:

4。同步代码块将从第 3 步获得对 StringBuffer 对象的锁定。

好吧,你不会那样做吧?

synchronized(this) {

您正在获取MySyncBlockTest 实例的锁定,在该实例上调用run() 方法。那......不会做任何事情。该资源没有争用;每个Thread 都有自己的MySyncBlockTest 实例。

【讨论】:

  • 知道了!我已将其更改为 synchronized(sb) 并且可以正常工作!
  • 不知道为什么会这样,但是有一个全局类变量没有private final Object lock = new Object(); synchronized(lock) { ...
  • @Alex 那是因为你的变量是一个全局实例变量,你必须将锁设为静态,否则它与使用 (this) 相同。
【解决方案2】:

你应该锁定 StringBuffer 对象

 synchronized(sb) {
            for (int i=0; i<10; i++) {
                System.out.print(sb);
            }

【讨论】:

    【解决方案3】:

    我也很困惑。 Brian提供的答案是正确的

    synchronized (this){
    

    用于获取实例的锁定。当有一个类的单个实例和多个线程访问它时,它会很有用。

    我编写了以下程序来证明这一点:

    package com.threads.chapter9;
    
    public class TestSunchronizedBlocksUsingRunnable implements Runnable {
    StringBuffer s;
    
    @Override
    public void run() {
        synchronized (this) {
            for (int i = 1; i <= 100; i++) {
                System.out.println(i);
            }
            char c = s.charAt(0);
            c++;
            s.setCharAt(0, c);
        }
    }
    
    TestSunchronizedBlocksUsingRunnable(StringBuffer s) {
        this.s = s;
    }
    
    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("A");
        TestSunchronizedBlocksUsingRunnable instance1 = new TestSunchronizedBlocksUsingRunnable(s);
        Thread thread1 = new Thread(instance1);
        Thread thread2 = new Thread(instance1);
        Thread thread3 = new Thread(instance1);
        thread1.start();
        thread2.start();
        thread3.start();
    }
    
    }
    

    上面的代码将显示相同的输出,但场景完全不同。所以你在同步块中使用的东西真的很重要。

    【讨论】:

      【解决方案4】:

      你想要的输出,单个对象的多个线程是可能的,试试这个方法

      public class MultiThreading implements Runnable {
      public static void main(String [] arg)
      {
      MultiThreading a=new MultiThreading(20);
      Thread t0=new Thread(a);   //
      Thread t1=new Thread(a);   // Multiple Threads of single object
      Thread t2=new Thread(a);   // 
      t0.start();
      t1.start();
      t2.start();
      }
      private int count;
      MultiThreading(int a)
      {this.count=a;
      }
      public void run()
      {
      synchronized(this){   
      String t_name=new String("");
      t_name=Thread.currentThread().getName().toString();
          for(int i=0;i<count;i++)
          if(t_name.equals("Thread-0".toString())) // mean t0
              System.out.print("A");
      
          else if(t_name.equals("Thread-1".toString())) // mean t1
              System.out.print("B");
      
          else if(t_name.equals("Thread-2".toString())) // mean t1
              System.out.print("C");
      System.out.print("\n");
                        }
      } // end of run
      }
      

      【讨论】:

        【解决方案5】:
         EXERCISE 9-2 from SCJP:
        Try this For Synchronozing on stringBuffer Object.
        It is giving required output.
        
        
        
        
        class letterThread extends Thread
        {
        StringBuffer putLetter;
        
        letterThread(StringBuffer str)
        {
            this.putLetter=str;
        }
        
        public void run()
        {
        
            synchronized (putLetter) {
        
                if(Thread.currentThread().getName().equals("th2"))
                {
                    this.putLetter=new StringBuffer("B");
                }
                else if(Thread.currentThread().getName().equals("th3"))
                {
                    this.putLetter=new StringBuffer("C");
                }
        
                for(int i=1;i<11;i++)
                {
                    System.out.print(putLetter+"");
                }
                System.out.println();
            }
        }   
        }
        
        public class Manager
        {
        public static void main(String args[])
        {
            StringBuffer str=new StringBuffer("A");
            letterThread th1=new letterThread(str);
            letterThread th2=new letterThread(str);
            letterThread th3=new letterThread(str);
        
            th1.setName("th1");
            th2.setName("th2");
            th3.setName("th3");
        
            th1.start();
            th2.start();
            th3.start();
        
        }
         }
        

        【讨论】:

          【解决方案6】:

          SCJP7 练习 13-2

          public class ThreadSyncronization extends Thread {
          
              StringBuffer sBuffer;
              public ThreadSyncronization(StringBuffer s,String name){
                  this.sBuffer=s;
                  this.setName(name);
              }
              public ThreadSyncronization(){
              }
              /**
               * @param args
               */
              public static void main(String[] args) {
                  StringBuffer ch = new StringBuffer("A");
                  Thread t1 = new ThreadSyncronization(ch,"first");
                  Thread t2 = new ThreadSyncronization(ch,"second");
                  Thread t3 = new ThreadSyncronization(ch,"third");
                  t1.start();
                  t2.start();
                  t3.start();
              }
          
              public void run(){
                  synchronized (sBuffer) {
                      System.out.println(this.getName());
                      for(int i=0;i<10;i++) {
                          System.out.print(sBuffer+":"+i+" ");
                          try{Thread.sleep(500);} catch(InterruptedException e) {System.out.println(e);}
                      }           
                      System.out.println();
                      // increment char
                     char c = this.sBuffer.charAt(0);
                     this.sBuffer.setCharAt(0, ++c);
                  }
          
              }
          
          }
          

          【讨论】:

            【解决方案7】:

            你可以替换

                    if (sb.charAt(0)=='A')
                        sb.setCharAt(0, 'B');
                    else
                        sb.setCharAt(0, 'C');
            

            sb.setCharAt(0, (char) (sb.charAt(0) + 1));
            

            【讨论】:

              【解决方案8】:

              包 com.practice.ThreadPackage;

              类 ThreadParent 扩展线程 {

              StringBuffer data;
              
              public void run() {
                  synchronized (this.data) {
              
                      System.out.println(this.getName());
              
                      for (int i = 0; i < 10; i++) {
              
                          System.out.print(this.data.toString());
                      }
              
                      System.out.println();
                      this.data.setCharAt(0, ((char) (this.data.charAt(0) + 1)));
                  }
              }
              
              ThreadParent(StringBuffer obj) {
                  this.data = obj;
              }
              

              }

              公共类线程类 { 公共静态 void main(String args[]) {

                  StringBuffer str = new StringBuffer("A");
                  ThreadParent obj = new ThreadParent(str);
                  ThreadParent obj1 = new ThreadParent(str);
                  ThreadParent obj2 = new ThreadParent(str);
                  obj.setName("Thread1");
                  obj1.setName("Thread2");
                  obj2.setName("Thread3");
                  obj.start();
                  obj1.start();
                  obj2.start();
              
              }
              

              }

              【讨论】:

              • 请解释您的答案,而不仅仅是转储代码。为什么这是一个好答案?它是如何解决问题的?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-07-13
              • 2010-09-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多