【问题标题】:How to distinguish threads that have locked to different instances?如何区分锁定到不同实例的线程?
【发布时间】:2019-08-14 18:54:48
【问题描述】:

我了解到线程可以锁定“资源”,比如说一个对象,它们正在使用,因此一次只允许使用和修改一个对象,这就是同步问题。我创建了一个类的两个不同实例并将其提供给我的线程,试图确保它们锁定不同的“资源”。他们如何仍然表现得好像他们已经锁定了相同的资源?我很困惑,因为我对线程没有任何经验和知识。

所以这是我从在线教程修改的代码,以尝试我的想法:

    public class TestThread {
        public static void main(String args[]) {
        PrintDemo PD1 = new PrintDemo("No.1"); //just prints from 1 to 5
        PrintDemo PD2 = new PrintDemo("No.2");

        ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD1 );
        ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD2 );

        T1.start();
        T2.start();
        // wait for threads to end
        try {
            T1.join();
            T2.join();
        } catch ( Exception e) {
            System.out.println("Interrupted");
        }
    }
}

class ThreadDemo extends Thread {
    private Thread t;
    private String threadName;
    PrintDemo  PD;

    ThreadDemo( String name,  PrintDemo pd) {
        threadName = name;
        PD = pd;
    }

    public void run() {
        synchronized(PD) {
            PD.printCount();
        }
        System.out.println("Thread " +  threadName + " exiting.");
    }

    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}

class PrintDemo {
    private String name;
    PrintDemo(String name) {
        this.name = name;
    }
    public void printCount() {
        try {
            for(int i = 5; i > 0; i--) {
            System.out.println(name + " Counter   ---   "  + i );
            }
        } catch (Exception e) {
        System.out.println("Thread  interrupted.");
        }
    }
}

每次跑步应该都不一样,但总是一样的:

输出:

开始线程 - 1 开始线程 - 2 1号柜台--- 5 1号柜台---4 1号柜台--- 3 1号柜台---2 1号计数器--- 1 线程 线程 - 1 退出。 2号柜台--- 5 2号柜台--- 4 2号柜台--- 3 2号柜台--- 2 2号柜台--- 1 线程 线程 - 2 退出。

编辑#1:我按照你的要求放置了整个代码。我还测试了代码而不覆盖开始。结果是一样的。

【问题讨论】:

  • 您多久运行一次代码?两次相同的输出是很有可能的,2000 次仍然是可能的,但不太可能。也许不要打印 5 次而是 1000 次,以便让线程有更多时间发散。
  • 为什么要覆盖start() 方法? ... 藏在那里的是什么?覆盖start() 是非常不寻常的。
  • 不要扩展Thread,而是实现Runnable。您可能通过覆盖Thread.start() 导致了问题,这会阻止Thread 在单独的线程中实际运行。不要这样做。
  • P.S.,这两个线程打印的行的交错应该每次都不同。只是它可能有所不同。我知道第一个线程总是在第二个线程开始之前运行完成有点可疑,但仅此而已 - 可疑 - 它并不能证明您的 Java 运行时或操作系统有任何问题。
  • @SolomonSlow 我编辑了这篇文章,所以你可以看到它是什么。我也尝试过没有覆盖开始。结果相同

标签: java multithreading thread-synchronization


【解决方案1】:

如果你添加一个

线程.sleep(1000)

在 PrintDemo 的每个刻度之间,您可能会看到两个线程都执行 5,然后是 4,然后是 3,等等。现在第一个线程太快了,它完成的速度比第二个线程可以由主线程。

这里同步没有效果,两个线程在不同的资源上同步,没有效果。在证明(使用 Thread.sleep)两个线程同时执行之后,然后在共享对象上添加同步,两个线程将一个接一个地完全执行,即使有等待。

【讨论】:

    【解决方案2】:

    问题出在您的ThreadDemo.start() 方法中。

    您的ThreadDemo 类是用extends Thread 声明的,但您实际上从未将它用作线程。相反,真正的线程对象是在ThreadDemo.start() 中创建的。

            t = new Thread (this, threadName);
            t.start ();
    

    以下是可能发生的情况:

    1. 主线程调用T1.start()。它会创建一个新线程,这需要一些时间,然后它会启动该线程。

    2. 新线程开始打印它的五行,而主线程同时调用T2.start()。

    3. T2.start() 调用创建另一个新线程,需要一些时间。同时,另一个线程仍在打印。它不会打印很多行,并且 system.out 被缓冲,所以很有可能,它能够在任何实际 I/O 发生之前打印所有行。同时……

    4. ...主线程仍在创建 T2 线程。这需要一些时间。

    5. 最后,主线程能够启动T2线程,打印它的五行,然后......

    ...故事结束。这就是它可能会下降的方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-07
      相关资源
      最近更新 更多