synchronized 和 beginTransaction 死锁的一个例子



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

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


  1. package com.mat.testdeadlock;  
  2.   
  3. import android.database.sqlite.SQLiteDatabase;  
  4. import android.os.Bundle;  
  5. import android.support.v7.app.AppCompatActivity;  
  6. import android.util.Log;  
  7.   
  8. public class MainActivity extends AppCompatActivity {  
  9.   
  10.     static Object sLocker = new Object();  
  11.   
  12.   
  13.     MySqlLiteHlelper myHelper;  
  14.   
  15.     Runnable run1 = new Runnable() {  
  16.         @Override  
  17.         public void run() {  
  18.   
  19.             try {  
  20.                 Thread.sleep(3000);  
  21.   
  22.                SQLiteDatabase db = myHelper.getWritableDatabase();  
  23.   
  24.                 Log.d(”DEADLOCK”“Before beginTransaction”);  
  25.                 db.beginTransaction();  
  26.                 Log.d(”DEADLOCK”“After beginTransaction”);  
  27.   
  28.                 Thread.sleep(3000);  
  29.   
  30.   
  31.                 Log.d(”DEADLOCK”“Before synchronized”);  
  32.                 synchronized (sLocker)  
  33.                 {  
  34.                     Log.d(”DEADLOCK”“In synchronized”);  
  35.                 }  
  36.   
  37.                 try{  
  38.                     db.setTransactionSuccessful();  
  39.                 }finally {  
  40.                     db.endTransaction();  
  41.                 }  
  42.   
  43.             } catch (Exception e) {  
  44.                 e.printStackTrace();  
  45.             }  
  46.   
  47.   
  48.   
  49.   
  50.         }  
  51.     };  
  52.   
  53.   
  54.   
  55.     Runnable run2 = new Runnable() {  
  56.         @Override  
  57.         public void run() {  
  58.   
  59.             try {  
  60.                 Thread.sleep(3000);  
  61.   
  62.   
  63.   
  64.   
  65.                 Log.d(”DEADLOCK”“Before synchronized”);  
  66.                 synchronized (sLocker)  
  67.                 {  
  68.                     Log.d(”DEADLOCK”“In synchronized”);  
  69.                     Thread.sleep(3000);  
  70.   
  71.                     SQLiteDatabase db = myHelper.getWritableDatabase();  
  72.   
  73.                     Log.d(”DEADLOCK”“Before beginTransaction”);  
  74.                     db.beginTransaction();  
  75.                     Log.d(”DEADLOCK”“After beginTransaction”);  
  76.   
  77.                     try{  
  78.                         db.setTransactionSuccessful();  
  79.                     }finally {  
  80.                         db.endTransaction();  
  81.                     }                }  
  82.   
  83.   
  84.   
  85.             } catch (Exception e) {  
  86.                 e.printStackTrace();  
  87.             }  
  88.   
  89.   
  90.   
  91.   
  92.         }  
  93.     };  
  94.   
  95.     @Override  
  96.     protected void onCreate(Bundle savedInstanceState) {  
  97.         super.onCreate(savedInstanceState);  
  98.         setContentView(R.layout.activity_main);  
  99.         myHelper = new MySqlLiteHlelper(this);  
  100.   
  101.   
  102.     }  
  103.   
  104.   
  105.   
  106.     @Override  
  107.     protected void onStart() {  
  108.         super.onStart();  
  109.   
  110.         new Thread(run1,“Thread-1”).start();  
  111.   
  112.         new Thread(run2,“Thread-2”).start();  
  113.     }  
  114. }  
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.


            </div>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要写一个产生synchronized的示例,可以创建两个线程,并在每个线程的代码块中嵌套调用两个共享的对象。这样,当一个线程持有一个并尝试获取另一个时,而另一个线程正好相反,就会发生。例如: ``` public class DeadlockExample { private static final Object lock1 = new Object(); private static final Object lock2 = new Object(); public static void main(String[] args) { Thread thread1 = new Thread(() -> { synchronized (lock1) { System.out.println("Thread 1 acquired lock1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("Thread 1 acquired lock2"); } } }); Thread thread2 = new Thread(() -> { synchronized (lock2) { System.out.println("Thread 2 acquired lock2"); synchronized (lock1) { System.out.println("Thread 2 acquired lock1"); } } }); thread1.start(); thread2.start(); } } ``` 在这个示例中,Thread 1首先获取lock1,然后尝试获取lock2。同时,Thread 2首先获取lock2,然后尝试获取lock1。由于两个线程都在相互等待对方释放,因此它们陷入了状态。这是因为两个线程都无法继续执行,直到它们都能同时获取所需的。 这个示例说明了在使用synchronized关键字时,如果没有正确处理的顺序和释放,就容易发生情况。为避免,可以在设计多线程应用程序时考虑的顺序和使用的范围,以及避免嵌套使用对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Synchronized](https://blog.csdn.net/weixin_44922129/article/details/122654024)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [详解Java中synchronized关键字的和内存占用问题](https://download.csdn.net/download/weixin_38695452/12796604)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java多线程并发环境下的synchronized实例](https://blog.csdn.net/zhangphil/article/details/127534524)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值