【问题标题】:Are these Threads synchronized?这些线程是否同步?
【发布时间】:2020-07-27 19:34:50
【问题描述】:

我的任务是创建 x 个线程,并以某种方式使用 MethodA 和 B,并同步它们,最后捕获一些异常。 我知道这不是一个很好的任务描述,但这就是我得到任务的方式。

所以问题是,这段代码能做什么,任务要求什么? 这些线程是否正确同步?

public class Test2{

    public static synchronized void doActionA(){
        System.out.println("Hi");
    }

    public static synchronized void doActionB(){
        System.out.println("Hello");
    }

    public static void main(String[] args) {
        
        for(int i = 0; i < 10000; ++i){
            try{
                new Thread(() -> {
                    doActionA();
                    doActionB();
                }).start();  
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                System.out.println(":)");
            }
        }
    }
}

【问题讨论】:

  • 我不太确定任务要求什么,但我可以说你的两个方法中的 synchronized 关键字完全没有做任何事情,因为 System.out.println() 本身就是一个同步方法。
  • 你想创建 10k 个线程吗?我不推荐它。通过 Executors 或 smth 使用 threadPool。第二件事是您的异常捕获没有用,因为它们无法在另一个线程中捕获异常。
  • @CharlieArmstrong:让我们假设,无论方法内部没有同步,那么这些线程会同步吗?两天后我要写一个编程考试,他们想看看我们是否理解这些概念,这个任务可能是考试中的这种,或者有点不同。
  • @cool:我可能只需要 100 个线程,但为了在控制台中打印,我做了 10k。执行者也将成为考试的一部分,所以我也可以这样尝试。
  • “同步它们”到底是什么意思?这将确保一次最多有一个线程正在执行doActionAB,但不能保证它们不会被穿插(例如,它可能会打印Hi Hello Hi HelloHi Hi Hello Hello 等)。

标签: java multithreading synchronized


【解决方案1】:

这基本上没用,是的。

您有 10000 个线程。每个线程将执行以下任务模式:

注意:获取对象“Test2.class”(代表 Test2 类的java.lang.Class 的实例;加载的整个 VM 中只有一个这样的对象。我们将其称为“储物柜”。

  1. 检查储物柜对象的“监控”线程。如果未设置,则将自己设置为locker的监控线程并继续。 (并以原子方式完成所有这些)。如果没有,则冻结线程,直到 'monitor' 再次为空,然后与其他 9999 个想要设置它的线程竞争; 9999 中只有一个获胜,将自己设置为监视器,然后继续。剩余的 9998 将冻结并等待下一轮。

  2. 执行doActionA。一直以来,9999 个线程都在玩弄拇指。

  3. 放弃储物柜(将自己取消设置为储物柜的监视器)。 9999 个其他线程全部飞入,将自己设置为监视器。只有其中一个会“获胜”。

  4. 再次获取锁(如果当前未设置,请将您自己设置为锁的监视器;否则,冻结并等待它可用......并以原子方式执行此操作)。根据 JVM 的实现,这个线程实际上可能会“获胜”,并立即夺回监视器,击败其他 9999 个线程。

  5. 执行doActionB。在这项工作中,9999 个线程在玩弄拇指,完全什么都不做。就等着吧。

  6. 放弃监视器并退出。噗。还剩 9999 个。

如您所知,这种模式很可能意味着这段代码的运行速度与刚才一样快:

for (int i = 0; i < 10000; i++) {
    doActionA();
    doActionB();
}

除了上述最有可能运行 FAR 更快,因为您的示例首先分配 1.25 GB 的内存只是为了存储堆栈(每个线程都需要一个堆栈,这里是祈祷您的堆栈“只有”128k 大,它们通常更大),并且浪费了大量时间来处理线程状态,几乎没有任何目的。

这不是你穿线的方式。

【讨论】:

    【解决方案2】:

    这些线程是否正确同步?

    以什么方式“同步”? “同步”的目的是什么?

    如果程序可以保证执行希望它执行的操作,则它是“正确的”。你想让这个程序做什么?

    做的是,它会打印一万行“Hi”,它会打印一万行“Hello”,它会打印它们命令。每一行都会完整的原因是System.out 对象使用同步来确保一次最多有一个线程可以执行println(...)。不按特定顺序打印行的原因是,程序中的线程之间没有任何 other 同步。

    【讨论】:

      【解决方案3】:

      这是您任务的主要部分: 最后捕获一些异常。

      问题是:这段代码能完成任务要求的工作吗?

      不,因为线程内部发生的异常无法像这样在线程外部捕获,请阅读以下问题以获取更多信息:

      How to catch an Exception from a thread

      【讨论】:

        猜你喜欢
        • 2016-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多