繁体   English   中英

方法同步,但由于非序列化的线程行为,代码产生随机结果

[英]Method synchronized , but code produces random result due to non-serialized thread behaviour

这是我的代码:

public class ThreadDemo {

public static void main(String args[]) throws Exception {
    Printer[] printers = new Printer[5];
    printers[0] = new Printer("@base");
    printers[1] = new Printer("#try");
    printers[2] = new Printer("!test");
    printers[3] = new Printer("^hello");
    printers[4] = new Printer("*world");

    for (Printer x : printers) {
        x.start();
    }

    try {
        for (Printer y : printers) {
            y.join();
        }
    } catch (InterruptedException e) {
        System.out.println(e);
    }
  }
}

class Printer extends Thread {
public Printer(String name) {
    super(name);
}

public void run() {
    print();
}

public synchronized void print() {
    for (int i = 0; i < 10; i++) {
        System.out.print(getName().charAt(0));
        try {
            sleep(100);
        } catch (InterruptedException e) {
            System.out.println(e + " occured");
        }
    }
  }
}

它导致了

@^!#**@^!#*#@!^@*#^!#^!*@^*@!#@!#*^@#^!*!@^#*#@*^! 

我的期望是所有符号将根据首先启动的线程序列化为@@@@@ ^^^^^。

调用sleep()会让其他线程继续进行直到当前线程的休眠时间,但我想不应该是同步方法的情况。

同步在这里不起作用。

该关键字确保您不能并行地在同一对象上调用相同的方法。

您正在不同的对象上调用它,因此即使没有关键字,结果也会相同!

(我宁愿假设您看到的结果实际上是由于在这里使用println()引起的。这是一个“非常慢”的操作,当超线程快速完成所有其他工作时,会引入“事实上的”同步。我试图找到一些关于它的其他信息,但这可能需要更多时间)

您的代码或我的问题会说您的期望是方法print在对象级别同步,并且您正在创建新的线程对象,启动线程并调用此方法。

因此,在这种情况下,每个方法在每个单独的线程对象上同步。 为了实现您期望的行为,我们可以使print方法保持静态并查看行为更改。 您将获得预期的结果,因为那时,方法print在一个Printer类锁实例上同步。 因此,即使不同的线程实例正在调用此方法,因为对于类只有一个锁,线程执行依次发生。

public static synchronized void print() {
    for (int i = 0; i < 10; i++) {
        System.out.print(Thread.currentThread().getName().charAt(0));
        try {
            sleep(100);
        } catch (InterruptedException e) {
            System.out.println(e + " occured");
        }
    }

}

@SolomonSlow - 所以必须纠正为'同步方法'可以同时在同一个对象上调用吗?

关于同步实例方法,您只需要知道一件事。 你需要知道这......

synchronized void Foobar() { ... }

...只是编写同步块的快捷方式。

void Foobar() {
    synchronized (this) {
        ...
    }
}

这两个方法声明都完全相同 因此,您知道或了解同步块行为的所有内容也可以应用于同步方法。

关于synchronized块的最重要的事情是,“不能同时在同一个对象上同步两个线程。” 如果您了解这一点,并且如果您知道同步方法只是同步块的快捷方式,那么您可以回答自己的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM