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);
}
}
}
答案 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
。它只保证一次只能有一个线程执行该方法。鉴于randomScore
为public
,这一点尤其如此。
修改允许我改写并尝试回答您的“更大问题”,而不是您在帖子中提出的明确问题。为了保证同步并且只有一个线程可以同时访问randomScore
,您必须实现某种锁定机制来控制变量的所有读取和写入。为了成功实现这一点,您必须定义一个控制对变量的访问的接口。你的例子中没有这样做过。您需要使用private
限制对变量的访问,然后创建允许操作变量的方法。您可以通过方法同步来完成此操作,但这可能并不总是正确的工作工具。
例如:
public void synchronized myMethod(){
//code
}
相当于
public void myMethod(){
synchronized(this){
//same code
}
}
因此,您正在使用方法级同步进行同步是在对象的实例上进行同步。如果您只是操纵对象内部的数据成员,那么这很好,但是如果您使用的变量在对象之外具有任何类型的范围(例如,在您的情况下为static
变量),这就会分崩离析)。那种情况下,您需要某种其他锁定机制。
答案 2 :(得分:1)
不,你没有正确使用它。写作是同步的,这没关系,但根本没有购买任何东西。没有同步,它的工作方式相同,因为
最好不要暴露需要同步的字段。