这可以“同步”工作吗?

时间:2011-02-13 23:47:39

标签: java multithreading

1
。这里使用同步的方式是否正确?
2。当一个线程访问randomScore以便其他线程无法访问randomScore时,它是否被锁定?如果只有changeRandomScore()可以访问randomScore变量,并且只有一个线程可以访问changeRandomScore(),那么一次只有一个线程可以访问randomScore。这是对的吗?

    import java.*;


public class StudentThread extends Thread {
    int ID;  
    public static int randomScore;

      StudentThread(int i) {
          ID = i;
      }

      public void run() {
          changeRandomScore();

          System.out.println("in run");
      }
public synchronized void changeRandomScore() {
    randomScore = (int) (Math.random()*1000);
}
public static void main(String args[]) throws Exception {
    for (int i = 1;i< 10 ;i++) 
    {
            StudentThread student = new StudentThread(5);

            student.start(); 
            Thread.sleep(100);
            System.out.println(randomScore);
    }             
}  
}

3 个答案:

答案 0 :(得分:6)

您在这里访问不同对象的synchronized-methods中的静态变量。这里的同步没有实际效果,因为每个线程都使用自己的监视器(在这种情况下是线程对象)。对于共享变量,您也应该使用共享监视器。

这是一个正确同步的变体:

public class StudentThread extends Thread {
  int ID;  
  private static int randomScore;
  private static final Object scoreLock = new Object();

  StudentThread(int i) {
     ID = i;
  }

  public void run() {
     changeRandomScore();

     System.out.println("in run");
  }
  public void changeRandomScore() {
     int tmp = (int) (Math.random()*1000);
     // no need to synchronize the random()-call, too.
     synchronized(scoreLock) {
        randomScore = tmp;
     }
  }
  public static void main(String args[]) throws Exception {
      for (int i = 1;i< 10 ;i++) 
      {
          StudentThread student = new StudentThread(5);

          student.start(); 
          Thread.sleep(100);
          synchronized(scoreLock) {
              System.out.println(randomScore);
          }
      }             
  }  
}

不同之处在于我们现在使用一个公共锁定对象(scoreLock)并将其用作synchronized块的参数,并且我们还在读取分数时在main方法中同步此对象。

或者,我们也可以声明方法public static synchronized void changeRandomScore()(这意味着它使用类对象作为监视器),并在main方法中同步StudentThread.class

是的,正如其他人所说:如果你想确保只在正确同步的情况下访问变量,就不要使它成为public

答案 1 :(得分:2)

正确,一次只能有一个线程访问方法changeRandomScore()。但是,这并不意味着多个线程将无法同时修改变量randomScore。它只保证一次只能有一个线程执行该方法。鉴于randomScorepublic,这一点尤其如此。

修改允许我改写并尝试回答您的“更大问题”,而不是您在帖子中提出的明确问题。为了保证同步并且只有一个线程可以同时访问randomScore,您必须实现某种锁定机制来控制变量的所有读取和写入。为了成功实现这一点,您必须定义一个控制对变量的访问的接口。你的例子中没有这样做过。您需要使用private限制对变量的访问,然后创建允许操作变量的方法。您可以通过方法同步来完成此操作,但这可能并不总是正确的工作工具。

例如:

public void synchronized myMethod(){
  //code
}

相当于

public void myMethod(){
  synchronized(this){
    //same code
  }
 }

因此,您正在使用方法级同步进行同步是在对象的实例上进行同步。如果您只是操纵对象内部的数据成员,那么这很好,但是如果您使用的变量在对象之外具有任何类型的范围(例如,在您的情况下为static变量),这就会分崩离析)。那种情况下,您需要某种其他锁定机制。

答案 2 :(得分:1)

不,你没有正确使用它。写作是同步的,这没关系,但根本没有购买任何东西。没有同步,它的工作方式相同,因为

  • 无论如何<{1}}访问
  • 读取未同步,因此您可能会看到陈旧的值

最好不要暴露需要同步的字段。