在最近的项目中有用到数据库这块儿,遇到了一些线程同步的问题,通过查资料希望弄懂这个问题.

多线程

多线程在java和android中都有用到,java中主要是为了提高CPU的利用效率,Android主要是为了防止产生ANR异常.

对应方法

1>提高效率的方法,多线程===>>>并发
2>ANR===>>>Android的主线程做耗时操作会产生ANR,因此把耗时的操作放在子线程中

多线程带来的问题:

1>线程安全
2>性能开销

下面用一个例子演示多线程带来的数据安全问题:
主页面,布局不贴了,就一个Button
MainActivity

package com.example.study0404;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends Activity {    CountDao countDao;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        countDao = new CountDao(MainActivity.this);        Button bt_add = (Button) findViewById(R.id.bt_add);        final List list1 = new ArrayList<>();        for (int i = 0; i < 100; i++) {            PersonModel model = new PersonModel();            model.setName("name-1-" + i);            model.setAge(1);            list1.add(model);        }        final List list2 = new ArrayList<>();        for (int i = 0; i < 30; i++) {            PersonModel model = new PersonModel();            model.setName("name-2-" + i);            model.setAge(2);            list2.add(model);        }        bt_add.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread() {                    public void run() {                        CountDao.addCountList(list1);                    };                }.start();                new Thread() {                    public void run() {                        CountDao.addCountList(list2);                    };                }.start();            }        });    }}

然后是数据库创建类:
DatabaseHelper

package com.example.study0404;import java.io.File;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.os.Environment;/** * 
 *     author : ada *     time   : 2017/03/30 *     desc   : *     version: 1.0 * 
*/
public class DatabaseHelper extends SQLiteOpenHelper { private final String sql = "CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement, name varchar(20), age INTEGER)"; public DatabaseHelper(Context context) { // super(context, Constant.DB_NAME, null, Constant.DB_VERSION); super(context, getMyDatabaseName(Constant.DB_NAME), null, Constant.DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } private static String getMyDatabaseName(String name) { String databasename = name; boolean isSdcardEnable = false; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) {// SDCard是否插入 isSdcardEnable = true; } String dbPath = null; if (isSdcardEnable) { dbPath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/study/database/"; } else {// 未插入SDCard,建在内存中 } File dbp = new File(dbPath); if (!dbp.exists()) { dbp.mkdirs(); } databasename = dbPath + databasename; return databasename; }}

然后是数据库业务类,很简单,就一个批量插入数据库的操作
CountDao

package com.example.study0404;import android.content.ContentValues;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.util.Log;import java.util.List;/** * 
 *     author : ada *     time   : 2017/03/30 *     desc   : *     version: 1.0 * 
*/
public class CountDao { private static DatabaseHelper helper; public CountDao(Context context) { helper = new DatabaseHelper(context); } public static void addCountList(List list) { if (!(list != null && list.size() > 0)) { return ; } String name = Thread.currentThread().getName(); Log.e("main","<<===start===>>>" + name); SQLiteDatabase db = helper.getWritableDatabase(); ContentValues values = new ContentValues(); for (PersonModel bean : list) { values.put("name", bean.getName()); values.put("age", bean.getAge()); long insert = db.insert("person", null, values); } db.close(); String success_name = Thread.currentThread().getName(); Log.e("main","<<===success===>>>" + success_name); }}

然后把程序跑起来,点击Button,开启两个线程同时操作数据库:

                new Thread() {                    public void run() {                        CountDao.addCountList(list1);                    };                }.start();                new Thread() {                    public void run() {                        CountDao.addCountList(list2);                    };                }.start();

程序抛异常了,日志如下:
Android中多线程同步问题_第1张图片

可以看到线程id为996的线程虽然后开始操作数据库,但是却先完成,这是因为list的数量为30,而list1的数量为100.耗时不同.
两个线程同时操作数据库,996的线程操作完后,把数据库关了,而这时995的线程还没插入完成,当其再次操作数据库时,就会抛出的java.lang.IllegalStateException异常.

那么怎么解决这个问题呢?
解决方法就是利用synchronized关键字,给方法加锁,使用同步方法操作数据库.

public static synchronized void addCountList(List list) {...}

这样当一个线程操作数据库时,另一个线程就会处于等待状态,等待前面的线程操作完成后,后面的线程才能操作数据库.

更多相关文章

  1. Unity5与Android交互通信(使用Android Studio2.4) 详细操作一
  2. Android:SNS客户端开发四:数据库操作(二)
  3. android 一个SQLite数据库多个数据表的基本使用框架 (带demo)
  4. Android Q 适配详细操作

随机推荐

  1. Android事件分发机制浅析
  2. 还在用android.support?该考虑迁移Android
  3. Android 2.3新特性:Web Apps概述
  4. Android系统架构概述
  5. [Android--Tool]不在Android设备运行而打
  6. Android Studio NDK开发在C代码中将Log输
  7. Android的两种数据存储方式分析(二)
  8. Android轻量型数据库SQLite详解
  9. android的logcat详细用法
  10. Android进程与内存及内存泄露