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



这是我的代码:

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在类锁的单个实例上同步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块,最重要的事情是,"没有两个线程可以同时在同一个对象上同步。 如果你明白这一点,如果你知道同步方法只是同步块的快捷方式,那么你就可以回答你自己的问题。

最新更新