遇到一个没想明白的问题。
    一个类的静态字段是当前类的子类,多线程同时实例化该类和子类时,线程卡住。

    有一个类DbWhere,它的一个静态字段NONE是DbWhere自身的子类。
    定义成这个结构,是想实现避免出现预期之外的条件为空:
    1、直接new DbWhere(),则条件不允许完全为空;
    2、如果预知条件为空,就要用DbWhere.NONE;
    3、如果有可能为空,则使用new EmptiableWhere()。

    目前已经通过删除EmptiableWhere,把emptiable作为DbWhere的一个字段,绕过了这个问题。
    但是造成问题的原理不清楚,记录一下。

    问题可以重现,不是必现,概率80%以上。
    git clone https://gitee.com/qdbp/db-where-test.git
    cd db-where-test/code
    test.bat

    DbWhere简化之后如下:

    1. public class DbWhere {
    2. /** 没有查询条件的空Where **/
    3. public static final DbWhere NONE = new ReadonlyWhere();
    4. public DbWhere() {
    5. log(this.getClass(), "DbWhere<init>()");
    6. }
    7. static void log(Class<?> clazz, String msg) {
    8. System.out.println(Thread.currentThread().getName() + ' ' + clazz.getSimpleName() + '-' + msg);
    9. }
    10. }
    11. /** 允许为空的查询条件 **/
    12. public class EmptiableWhere extends DbWhere {
    13. public EmptiableWhere() {
    14. log(this.getClass(), "DbWhere<init>()");
    15. }
    16. }
    17. /** 只读查询条件 **/
    18. public class ReadonlyWhere extends EmptiableWhere {
    19. public ReadonlyWhere() {
    20. log(this.getClass(), "DbWhere<init>()");
    21. }
    22. }

    两个测试线程类

    1. public class DbWhereThread extends Thread {
    2. public void run() {
    3. new DbWhere();
    4. }
    5. }
    1. public class EmptiableWhereThread extends Thread {
    2. public void run() {
    3. new EmptiableWhere();
    4. }
    5. }

    测试1,多线程实例化父类DbWhere,没有问题

    1. public class DbWhereTest1 {
    2. public static void main(String[] args) {
    3. for (int i = 0; i < 3; i++) {
    4. new DbWhereThread().start();
    5. }
    6. }
    7. }

    测试2,多线程实例化子类EmptiableWhere,没有问题

    1. public class DbWhereTest2 {
    2. public static void main(String[] args) {
    3. for (int i = 0; i < 3; i++) {
    4. new EmptiableWhereThread().start();
    5. }
    6. }
    7. }

    测试3,先实例化DbWhere,再多线程同时实例化父类和子类,没有问题

    1. public class DbWhereTest3 {
    2. public static void main(String[] args) {
    3. new DbWhere();
    4. for (int i = 0; i < 3; i++) {
    5. new DbWhereThread().start();
    6. new EmptiableWhereThread().start();
    7. }
    8. }
    9. }

    测试4,多线程同时实例化父类和子类,线程卡住了

    1. public class DbWhereTest4 {
    2. public static void main(String[] args) {
    3. System.out.println("DbWhereTest4");
    4. for (int i = 0; i < 3; i++) {
    5. new DbWhereThread().start();
    6. new EmptiableWhereThread().start();
    7. }
    8. }
    9. }

    从线程Dump看,都卡在构造函数这里

    1. "Thread-5" #16 prio=5 os_prio=0 tid=0x00000000226f0000 nid=0x6284 in Object.wait() [0x000000002477f000]
    2. java.lang.Thread.State: RUNNABLE
    3. at EmptiableWhereThread.run(EmptiableWhereThread.java:3)
    4. Locked ownable synchronizers:
    5. - None
    6. "Thread-4" #15 prio=5 os_prio=0 tid=0x00000000226ed800 nid=0x5d20 in Object.wait() [0x000000002467f000]
    7. java.lang.Thread.State: RUNNABLE
    8. at DbWhereThread.run(DbWhereThread.java:3)
    9. Locked ownable synchronizers:
    10. - None
    11. "Thread-3" #14 prio=5 os_prio=0 tid=0x00000000226ec800 nid=0x4640 in Object.wait() [0x000000002457f000]
    12. java.lang.Thread.State: RUNNABLE
    13. at EmptiableWhereThread.run(EmptiableWhereThread.java:3)
    14. Locked ownable synchronizers:
    15. - None
    16. "Thread-2" #13 prio=5 os_prio=0 tid=0x00000000226e8000 nid=0x409c in Object.wait() [0x000000002447f000]
    17. java.lang.Thread.State: RUNNABLE
    18. at DbWhereThread.run(DbWhereThread.java:3)
    19. Locked ownable synchronizers:
    20. - None
    21. "Thread-1" #12 prio=5 os_prio=0 tid=0x00000000226e5800 nid=0x6760 in Object.wait() [0x000000002437e000]
    22. java.lang.Thread.State: RUNNABLE
    23. at EmptiableWhereThread.run(EmptiableWhereThread.java:3)
    24. Locked ownable synchronizers:
    25. - None
    26. "Thread-0" #11 prio=5 os_prio=0 tid=0x00000000226e2000 nid=0x62c8 in Object.wait() [0x000000002427e000]
    27. java.lang.Thread.State: RUNNABLE
    28. at DbWhere.<clinit>(DbWhere.java:4)
    29. at DbWhereThread.run(DbWhereThread.java:3)
    30. Locked ownable synchronizers:
    31. - None