Java Class装载时的问题

上代码

public class DoSome {
    private static final DoSome instance = new DoSome();

    private DoSome(){
        System.out.println("ready");
        CountDownLatch await = new CountDownLatch(1);
        doing();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread ready");
                doing();
                await.countDown();
            }
        }).start();

        try {
            await.await(10000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("done");
    }

    private static void doing() {
        System.out.println("doing");
    }

    public static void main(String[] args) {
    }
}

运行主方法得到结果如下

ready
doing
thread ready
// 中间阻塞了10s
done
doing

问题分析

在装载DoSome时,因为我们存在 static final DoSome instance = new DoSome();,会去执行构造函数。当前构造函数中可以执行doing(),线程中也可以输出代码,但是当线程执行到doing()的时候,阻塞了。直至await结束了之后(可能是类的装载完成了),线程才可以执行doing()

猜测

所以当Class没有装载完成时,其他线程是无法访问当前Class的静态方法?

阅读 237
评论
    2 个回答

    是的,Java要求类加载是同步的,同一个类不能同时加载

      • 190

      不是。

      错误1:直至await结束了之后(可能是类的装载完成了),线程才可以执行doing()

      这个是因为,你那边设置了时间,如果直接用await.await();你会发现控制台已经在等待,没有输出done和doing

      错误2。所以当Class没有装载完成时,其他线程是无法访问当前Class的静态方法

      static方法,是存在方法区的,对象是在堆中,所以和对象是否创建没有关系。请看下面的例子,控制台先输出ready,然后休眠3秒,这个时候,类还没创建好,此时我另外一个线程,在一秒后会输出doing,再过一下,输出done。

      原因是因为死锁了(我也不知道为什么死锁了,有人知道请告知我),怎么找死锁,请参考这篇文章

      public class DoSome1 {
      
          private DoSome1(){
              System.out.println("ready");
              try {
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println("done");
          }
      
          private static void doing() {
              System.out.println("doing");
          }
      
          public static void main(String[] args) throws InterruptedException {
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          Thread.sleep(1000);
                          DoSome1.doing();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              }).start();
              DoSome1 instance = new DoSome1();
      
          }
      }
        撰写回答

        登录后参与交流、获取后续更新提醒