synchronized 和 beginTransaction 死锁的一个例子

来源:互联网 发布:美工设计学习 编辑:程序博客网 时间:2024/06/05 19:25


这是一个及其诡异的死锁,很少有人意识到,在Androind中,SQLiteDatabase.beginTransaction的实现里,也要等到SQLiteConnectionPool中此db的primaryConnect可用才行。也就是说,beginTransaction和endTransaction也在某种程序上等同于锁定和解锁,在和synchronized(sLocker)嵌套使用时,同样要考虑死锁的问题。 

一般来讲,如果看到SQLiteConnectionPool的很长的超时警告,就要考虑死锁的可能性。下面是死锁的模拟:


package com.mat.testdeadlock;import android.database.sqlite.SQLiteDatabase;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class MainActivity extends AppCompatActivity {    static Object sLocker = new Object();    MySqlLiteHlelper myHelper;    Runnable run1 = new Runnable() {        @Override        public void run() {            try {                Thread.sleep(3000);               SQLiteDatabase db = myHelper.getWritableDatabase();                Log.d("DEADLOCK", "Before beginTransaction");                db.beginTransaction();                Log.d("DEADLOCK", "After beginTransaction");                Thread.sleep(3000);                Log.d("DEADLOCK", "Before synchronized");                synchronized (sLocker)                {                    Log.d("DEADLOCK", "In synchronized");                }                try{                    db.setTransactionSuccessful();                }finally {                    db.endTransaction();                }            } catch (Exception e) {                e.printStackTrace();            }        }    };    Runnable run2 = new Runnable() {        @Override        public void run() {            try {                Thread.sleep(3000);                Log.d("DEADLOCK", "Before synchronized");                synchronized (sLocker)                {                    Log.d("DEADLOCK", "In synchronized");                    Thread.sleep(3000);                    SQLiteDatabase db = myHelper.getWritableDatabase();                    Log.d("DEADLOCK", "Before beginTransaction");                    db.beginTransaction();                    Log.d("DEADLOCK", "After beginTransaction");                    try{                        db.setTransactionSuccessful();                    }finally {                        db.endTransaction();                    }                }            } catch (Exception e) {                e.printStackTrace();            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        myHelper = new MySqlLiteHlelper(this);    }    @Override    protected void onStart() {        super.onStart();        new Thread(run1,"Thread-1").start();        new Thread(run2,"Thread-2").start();    }}



结果:


04-22 12:28:38.473 972-1006/com.mat.testdeadlock D/DEADLOCK: Before synchronized

04-22 12:28:38.473 972-1006/com.mat.testdeadlock D/DEADLOCK: In synchronized

04-22 12:28:38.551 972-1005/com.mat.testdeadlock D/DEADLOCK: Before beginTransaction

04-22 12:28:38.551 972-1005/com.mat.testdeadlock D/DEADLOCK: After beginTransaction

04-22 12:28:41.474 972-1006/com.mat.testdeadlock D/DEADLOCK: Before beginTransaction  ---此时,1005 hold db, 1006 waiting sLocker  

04-22 12:28:41.552 972-1005/com.mat.testdeadlock D/DEADLOCK: Before synchronized        --此时,1006 hold sLocker, 1005 waiting db

04-22 12:29:11.474 972-1006/com.mat.testdeadlock W/SQLiteConnectionPool: The connection pool for database '/data/user/0/com.mat.testdeadlock/databases/my.db' has been unable to grant a connection to thread 2462 (Thread-2) with flags 0x2 for 30.000002 seconds. Connections: 0 active, 1 idle, 0 available

.

.

.

04-22 12:41:41.488 972-1006/com.mat.testdeadlock W/SQLiteConnectionPool: The connection pool for database '/data/user/0/com.mat.testdeadlock/databases/my.db' has been unable to grant a connection to thread 2462 (Thread-2) with flags 0x2 for780.01404 seconds. Connections: 0 active, 1 idle, 0 available.


0 0
原创粉丝点击