Android中多线程同步问题

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

多线程

多线程在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) {
...
}

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

发布了12 篇原创文章 · 获赞 0 · 访问量 5544
展开阅读全文

android 多线程线程如何同步

05-30

定义了三个线程public Thread thread1,thread2,thread3;分别执行操作,请问如何让这三个线程同步,贴出我的代码 public class MainActivity extends AppCompatActivity { public static SQLiteDatabase db; public static Person person; public Thread thread1,thread2,thread3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null); db.execSQL("DROP TABLE IF EXISTS person"); db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)"); person = new Person(); person.name = "john"; person.age = 30;; db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age}); person.name = "david"; person.age = 33; ContentValues cv = new ContentValues(); cv.put("name", person.name); cv.put("age", person.age); person.name = "dasdd"; person.age = 33; ContentValues cv1 = new ContentValues(); cv1.put("name", person.name); cv1.put("age", person.age); person.name = "dasdd"; person.age = 88; ContentValues cv2 = new ContentValues(); cv2.put("name", person.name); cv2.put("age", person.age); db.insert("person", null, cv); db.insert("person", null, cv1); db.insert("person", null, cv2); thread1 = new Thread(new Runnable() { @Override public void run() { person.name = "abc"; person.age = 100; ContentValues cv = new ContentValues(); cv.put("name", person.name); cv.put("age", person.age); person.name = "axt"; person.age = 67; ContentValues cv1 = new ContentValues(); cv1.put("name", person.name); cv1.put("age", person.age); int i =1; while (i<10){ db.insert("person", null, cv); db.insert("person", null, cv1); i++; } } }); thread1.start();; thread2 = new Thread(new Runnable() { @Override public void run() { person.name = "张"; person.age = 47; ContentValues cv1 = new ContentValues(); cv1.put("name", person.name); cv1.put("age", person.age); person.name = "QQQ"; person.age = 999; ContentValues cv = new ContentValues(); cv.put("name", person.name); cv.put("age", person.age); db.insert("person", null, cv); db.insert("person", null, cv1); } }); thread2.start(); thread3 =new Thread(new Runnable() { @Override public void run() { Cursor c= db.rawQuery("SELECT * FROM person WHERE age >= ?",new String[]{"30"}); while (c.moveToNext()) { int _id = c.getInt(c.getColumnIndex("_id")); String name = c.getString(c.getColumnIndex("name")); int age = c.getInt(c.getColumnIndex("age")); Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age); //c.close(); } } }); thread3.start(); // // db.delete("person", "age < ?", new String[]{"35"}); // db.close(); // deleteDatabase("test.db"); } public class Person{ String name; Integer age; } public synchronized void same(){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 求大神指点synchronized方法要怎么用? 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览