Android中多线程同步问题

    xiaoxiao2021-03-25  72

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

    多线程

    多线程在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<PersonModel> 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<PersonModel> 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; /** * <pre> * author : ada * time : 2017/03/30 * desc : * version: 1.0 * </pre> */ 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; /** * <pre> * author : ada * time : 2017/03/30 * desc : * version: 1.0 * </pre> */ public class CountDao { private static DatabaseHelper helper; public CountDao(Context context) { helper = new DatabaseHelper(context); } public static void addCountList(List<PersonModel> 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();

    程序抛异常了,日志如下:

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

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

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

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

    转载请注明原文地址: https://ju.6miu.com/read-39266.html

    最新回复(0)