1.起因

程序莫名其妙出了
error:java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
就是在使用同步锁的时候,是锁的对象是空的。很是奇怪,看代码没觉得啊。打印一下,确实是空的,Why?

2. 代码,看出问题?

代码逻辑简化如下:

  1. public class SynTest {
  2. public static void main(String[] args) {
  3. System.out.println(LockInstance.string);
  4. }
  5. }
  6. class LockInstance {
  7. public static String string = getString();
  8. private static byte[] sLock = new byte[0];
  9. public static LockInstance getInstance() {
  10. synchronized (sLock){
  11. return new LockInstance();
  12. }
  13. }
  14. private static String getString(){
  15. return LockInstance.getInstance().getApplicationContext();
  16. }
  17. public String getApplicationContext() {
  18. return "string";
  19. }
  20. }

没问题啊?

猜一下结果输出?出错拉!!

  1. Exception in thread "main" java.lang.ExceptionInInitializerError
  2. at SynTest.main(SynTest.java:3)
  3. Caused by: java.lang.NullPointerException
  4. at LockInstance.getInstance(SynTest.java:11)
  5. at LockInstance.getString(SynTest.java:16)
  6. at LockInstance.<clinit>(SynTest.java:8)
  7. ... 1 more

3 为什么?

本质上是没有理解类加载的过程导致出错的。来理一下思路
首先在第一次调用 LockInstane 的静态方法的时候,类会进行初始化。那么类的初始化是有一个过程的。按声明的静态变量进行初始化,再是类的静态块,最后再是执行调用的静态方法。按上面的代码,问题错在 类初始化的时候,由于静态的成员变量调用了静态方法进行初始化,但是在里面用的变量却还没来得及初始化。

4 解决办法

如果类的成员变量的初始化需要用到类的成员变量,请保证在这之前已经用到的变量已经初始化了。

修改方法,放到前面就可以了。

  1. private static byte[] sLock = new byte[0];
  2. public static String string = getString();

测试运行成功。