Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

死锁问题 #101

Closed
laizuling opened this issue Sep 7, 2016 · 7 comments
Closed

死锁问题 #101

laizuling opened this issue Sep 7, 2016 · 7 comments

Comments

@laizuling
Copy link

主线程
"main" prio=5 tid=1 Blocked
| group="main" sCount=1 dsCount=0 obj=0x746f9a50 self=0xf4736a00
| sysTid=17043 nice=0 cgrp=bg_non_interactive sched=0/0 handle=0xf71b8de4
| state=S schedstat=( 1381247238 86682835 492 ) utm=127 stm=11 core=5 HZ=100
| stack=0xff657000-0xff659000 stackSize=8MB
| held mutexes=
at com.meizu.lifekit.entity.UserSingleton.(UserSingleton.java:22)

  • waiting to lock <0x0fd0e4f2> (a java.lang.Class<org.litepal.crud.DataSupport>) held by thread 16
    at com.meizu.lifekit.entity.UserSingleton.(UserSingleton.java:21)
    at com.meizu.lifekit.entity.UserSingleton$InstanceHolder.(UserSingleton.java:180)
    at com.meizu.lifekit.entity.UserSingleton.getInstance(UserSingleton.java:30)
    at com.meizu.lifekit.data.mainpage.NewHomeFragment.(NewHomeFragment.java:82)
    at java.lang.Class.newInstance!(Native method)

TID16:
"LifeKitApplication" prio=5 tid=16 Blocked
| group="main" sCount=1 dsCount=0 obj=0x132db8e0 self=0xf395b900
| sysTid=17067 nice=0 cgrp=bg_non_interactive sched=0/0 handle=0xd9418930
| state=S schedstat=( 2762923 1967693 9 ) utm=0 stm=0 core=1 HZ=100
| stack=0xd9316000-0xd9318000 stackSize=1038KB
| held mutexes=
kernel: __switch_to+0x74/0x8c
kernel: futex_wait_queue_me+0xd8/0x168
kernel: futex_wait+0xe4/0x234
kernel: do_futex+0x184/0xa14
kernel: compat_SyS_futex+0x7c/0x168
kernel: el0_svc_naked+0x20/0x28
native: #00 pc 00017698 /system/lib/libc.so (syscall+28)
native: #1 pc 000e8985 /system/lib/libart.so (_ZN3art17ConditionVariable4WaitEPNS_6ThreadE+80)
native: #2 pc 0029fb2b /system/lib/libart.so (_ZN3art7Monitor4LockEPNS_6ThreadE+394)
native: #3 pc 002a25cb /system/lib/libart.so (_ZN3art7Monitor12MonitorEnterEPNS_6ThreadEPNS_6mirror6ObjectE+270)
native: #4 pc 002d775d /system/lib/libart.so (_ZN3art10ObjectLockINS_6mirror6ObjectEEC2EPNS_6ThreadENS_6HandleIS2_EE+24)
native: #5 pc 0012bfdf /system/lib/libart.so (_ZN3art11ClassLinker15InitializeClassEPNS_6ThreadENS_6HandleINS_6mirror5ClassEEEbb.part.593+94)
native: #6 pc 0012ce93 /system/lib/libart.so (_ZN3art11ClassLinker17EnsureInitializedEPNS_6ThreadENS_6HandleINS_6mirror5ClassEEEbb+82)
native: #7 pc 002aea0d /system/lib/libart.so (_ZN3artL18Class_classForNameEP7_JNIEnvP7_jclassP8_jstringhP8_jobject+452)
native: #8 pc 0025eb19 /data/dalvik-cache/arm/system@framework@boot.oat (Java_java_lang_Class_classForName__Ljava_lang_String_2ZLjava_lang_ClassLoader_2+132)
at java.lang.Class.classForName!(Native method)

  • waiting to lock <0x081409ec> (a java.lang.Class<com.meizu.lifekit.entity.User>) held by thread 1
    at java.lang.Class.forName(Class.java:324)
    at java.lang.Class.forName(Class.java:285)
    at org.litepal.LitePalBase.getSupportedFields(LitePalBase.java:170)
    at org.litepal.crud.DataHandler.query(DataHandler.java:124)
    at org.litepal.crud.QueryHandler.onFindLast(QueryHandler.java:96)
    at org.litepal.crud.DataSupport.findLast(DataSupport.java:576)
  • locked <0x0fd0e4f2> (a java.lang.Class<org.litepal.crud.DataSupport>)
    at org.litepal.crud.DataSupport.findLast(DataSupport.java:561)
  • locked <0x0fd0e4f2> (a java.lang.Class<org.litepal.crud.DataSupport>)
    at com.meizu.lifekit.LifeKitApplication$ApplicationHandler.handleMessage(LifeKitApplication.java:117)
    at android.os.Handler.dispatchMessage(Handler.java:111)
    at android.os.Looper.loop(Looper.java:207)
    at android.os.HandlerThread.run(HandlerThread.java:61)

表User类实例化时,同时查询数据库,互相持有锁造成死锁
User实例化时持有User class锁申请父类DataSupport class锁,查询User表时持有DataSupport class锁申请User class锁,互相持有对方资源不释放死锁了。

@laizuling
Copy link
Author

版本v1.3.1

@laizuling
Copy link
Author

laizuling commented Sep 7, 2016

UserSingleton里面实例化的时候会实例化一个默认的User

public final class UserSingleton {
    private User mUser = new User();
    private List<OnUserInfoChangeListener> mListenerList;

    private UserSingleton() {
        mListenerList = new ArrayList<>();
    }

@guolindev
Copy link
Owner

LitePal不处理你的逻辑锁的问题,LitePal内部锁只会控制不让多个任务同时操作数据库,数据库操作一旦完成就会立刻将锁释放掉,你的逻辑里出现死锁需要自己去解决。

@laizuling
Copy link
Author

这样的话意思是如果你子线程在查询数据库,主线程就不能进行该类对象的实例化了?

@laizuling
Copy link
Author

或者说我需要另外加锁才能在主线程进行该表类对象的实例化?这样会不会有点麻烦了?

@kmfish
Copy link

kmfish commented Aug 24, 2017

我们也是遇到了这个问题,在数据库查询期间,其他线程通过json反序列化 实例化该表类对象,就死锁了。
LitePal在查询期间加锁,在 LitePalBase.getSupportedFields里通过Class.forName去加载该class,但forName默认会去初始化该类,这就可能和其他线程里的初始化互锁了。这里的forName可以用带参数的版本,initialize设false,不用初始化避免死锁。
synchronized (DataSupport.class) 或者这里不要锁这个基类,换成其他类也行啊。

@laizuling
Copy link
Author

laizuling commented Aug 31, 2017

实例化User类的时候发生的事情,先初始化User类的过程中持有User.class锁,发现DataSupport是父类,此时User.class处于being_initialized状态,尝试初始化DataSupport类(想进入being_initialized状态),但是DataSupport.class已经被子线程的查询操作访问先进行初始化(已经进入了being_initialized状态,但查询线程需要等待User的being_initialized状态完成),所以主线程实例化User的时候持有User.class锁,等待DataSupport.class锁;而子线程的查询User操作的时候,先访问的DataSupport类,先初始化DataSupport类,等待访问User.class锁,顺序相反地持锁,死锁BOOM!如果您坚持认为这个是程序逻辑死锁的话,那我们使用LitePal时就不能查询的时候同时在另一个线程实例化该类了。算是库的缺陷么?
类初始化过程持锁的原因 参考链接:https://yq.aliyun.com/articles/73595

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants