Android SQLite多线程读写和线程同步源码分析
2018-03-17 16:56
330 查看
没啥诀窍,只需保证几个线程都是用的一个SQLiteDataBase对象就行了。
如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作的是同一个数据库,也就是同一个db文件,这个就是这篇博客的重点了
(ps:使用到的代码将在博文结尾贴出)
writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil);
readThread_three = new SQLReadThread("three",true,sqLiteUtil);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
可以看出同一个SQLiteDataBase对象多线程读写操作没问题
writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil_two);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
因为无限循环的时候没有设置sleep,模仿多次读写操作,所以log很多重复的
03-17 16:39:16.634 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.634 29175-29295/com.example.zth.seven V/zzw: one query
03-17 16:39:16.636 29175-29296/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.638 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:16.640 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.640 29175-29297/com.example.zth.seven V/zzw: three query
03-17 16:39:16.642 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
。。。。。。
03-17 16:39:16.650 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:16.665 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.668 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.975 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.977 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.980 29175-29294/com.example.zth.seven V/zzw: write update
。。。。。。。。。。
03-17 16:39:17.081 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.081 29175-29297/com.example.zth.seven V/zzw: three query
03-17 16:39:17.083 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.083 29175-29295/com.example.zth.seven V/zzw: one query
03-17 16:39:17.083 29175-29296/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.084 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:17.085 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
。。。。。。。。。。。
运行正常
两个个子线程执行update函数,所持有的SQLiteDataBase对象是sqLiteUtil,而其他三个子线程执行query函数,所持有的SQLiteDataBase对象是sqLiteUtil_two,
writethread = new SQLWritethread("write",true,sqLiteUtil);
writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil_two);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
一开始几秒还好,然后就说子线程执行的query函数有问题
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (Sqlite code 5), (OS error - 2:No such file or directory)
看来在不同线程下读操作不能在多个SQLiteDataBase对象进行写操作的时候来完成
如果是读操作那边有两个SQLiteDataBase对象呢 writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
// writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
结果一样
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (Sqlite code 14), (OS error - 24:Too many open files)
public class SQLiteActivity extends Activity {
/** Called when the activity is first created. */
//声明各个按钮
private Button createBtn;
private Button insertBtn;
private Button updateBtn;
private Button queryBtn;
private Button deleteBtn;
private Button ModifyBtn,btn_thread_start,btn_thread_stop;
private SQLiteUtil sqLiteUtil,sqLiteUtil_two;
private SQLWritethread writethread,writethread_two;
private SQLReadThread readThread_one;
private SQLReadThread readThread_two;
private SQLReadThread readThread_three;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_five);
//调用creatView方法
creatView();
//setListener方法
setListener();
}
//通过findViewById获得Button对象的方法
private void creatView(){
createBtn = (Button)findViewById(R.id.createDatabase);
updateBtn = (Button)findViewById(R.id.updateDatabase);
insertBtn = (Button)findViewById(R.id.insert);
ModifyBtn = (Button)findViewById(R.id.update);
queryBtn = (Button)findViewById(R.id.query);
deleteBtn = (Button)findViewById(R.id.delete);
btn_thread_start = (Button)findViewById(R.id.btn_thread_start);
btn_thread_stop = (Button)findViewById(R.id.btn_thread_stop);
}
//为按钮注册监听的方法
private void setListener(){
createBtn.setOnClickListener(new CreateListener());
updateBtn.setOnClickListener(new UpdateListener());
insertBtn.setOnClickListener(new InsertListener());
ModifyBtn.setOnClickListener(new ModifyListener());
queryBtn.setOnClickListener(new QueryListener());
deleteBtn.setOnClickListener(new DeleteListener());
btn_thread_start.setOnClickListener(new ThreadStartListener());
btn_thread_stop.setOnClickListener(new ThreadStopListener());
sqLiteUtil = new SQLiteUtil(this);
sqLiteUtil_two = new SQLiteUtil(this);
}
//创建数据库的方法
class CreateListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.initSQL();
}
}
//升级数据库的方法
class UpdateListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.upgradeSQL();
}
}
//插入数据的方法
class InsertListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.insertSQL();
}
}
//查询数据的方法
class QueryListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.querySQL();
}
}
//修改数据的方法
class ModifyListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.updateSQL();
}
}
//删除数据的方法
class DeleteListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.deleteSQL();
}
}
class ThreadStartListener implements OnClickListener{
@Override
public void onClick(View v) {
writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
// writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
}
}
class ThreadStopListener implements OnClickListener{
@Override
public void onClick(View v) {
writethread.setState(false);
// writethread_two.setState(false);
readThread_one.setState(false);
readThread_two.setState(false);
readThread_three.setState(false);
}
}
@Override
protected void onDestroy() {
writethread.setState(false);
// writethread_two.setState(false);
readThread_one.setState(false);
readThread_two.setState(false);
readThread_three.setState(false);
sqLiteUtil_two.closeSQL();
sqLiteUtil.closeSQL();
super.onDestroy();
}
}
题外话:你是不是觉得我应该使用getWriteableDataBase,但我可以负责的告诉你基本两种函数得到的SQLiteDatabase对象都能进行读写操作,只会在存储空间不够的情况下才有点区别。(ps:我的64G大存储可能吗)
SQLite线程同步源码分析
加点东西,看了点源码分析了一下SQLite如何完成线程同步,我的切入点就是SQLite如何自己实现的线程同步
我们首先分析读操作也就是query命令如何实现线程同步,跟着我command加鼠标左键看源码
首先query方法里又放了一个query,很正常,加默认参数,(ps:源码在SQLiteDatabase类)
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
}
还是加默认参数,(ps:源码在SQLiteDatabase类) public Cursor query(boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, null);
}
到了真正实现query方法的源码了(ps:源码在SQLiteDatabase类)
public Cursor queryWithFactory(CursorFactory cursorFactory,
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
acquireReference();
try {
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
findEditTable(table), cancellationSignal);
} finally {
releaseReference();
}
}
看到了acquireReference()和releaseReference(),不是感觉很可疑,不要急,我们再看看rawQueryWithFactory方法的源码(ps:源码在SQLiteDatabase类)
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}
又看到了这个两个函数,但是我们还要看看driver.query源码(ps:源码在SQLiteCursorDriver类)
Cursor query(CursorFactory factory, String[] bindArgs);
没了,只是个接口函数,好了我们再来看看acquireReference()和releaseReference()的源码,(ps:源码在SQLiteClosable类)
public void acquireReference() {
synchronized(this) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
"attempt to re-open an already-closed object: " + this);
}
mReferenceCount++;
}
}
public void releaseReference() {
boolean refCountIsZero = false;
synchronized(this) {
refCountIsZero = --mReferenceCount == 0;
}
if (refCountIsZero) {
onAllReferencesReleased();
}
}
感觉是通过Synchronized同步锁锁住自己,来完成线程同步,因为SQLiteDatabase是这个抽象类SQLiteClosable的子类,还不能做判断,再看看onAllReferencesReleased()源码
protected abstract void onAllReferencesReleased();
抽象函数,。。。。。。没关系,看看SQLiteDatabase如何实现这个抽象函数
@Override
protected void onAllReferencesReleased() {
dispose(false);
}
private void dispose(boolean finalized) {
final SQLiteConnectionPool pool;
synchronized (mLock) {
if (mCloseGuardLocked != null) {
if (finalized) {
mCloseGuardLocked.warnIfOpen();
}
mCloseGuardLocked.close();
}
pool = mConnectionPoolLocked;
mConnectionPoolLocked = null;
}
if (!finalized) {
synchronized (sActiveDatabases) {
sActiveDatabases.remove(this);
}
if (pool != null) {
pool.close();
}
}
}
又是同步锁,来防止同时执行多次close(),源码就看到这里,我们再看看官方说明,(PS:百度翻译的)
acquireReference()
获取对对象的引用。
close()
释放一个对对象的引用,如果最后一个引用被释放,则关闭对象。
releaseReference()
释放一个对对象的引用,如果最后一个引用被释放,则关闭对象。
但是这里我们注意一下mReferenceCount的默认值为1
private int mReferenceCount = 1;
acquireReference()和releaseReference()时是成双成对的出现,一个加,一个减,除非我们调用一次close,否则他不会关闭对象的
如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作的是同一个数据库,也就是同一个db文件,这个就是这篇博客的重点了
(ps:使用到的代码将在博文结尾贴出)
第一种情况:一个SQLiteDataBase对象不同线程
两个子线程执行修改数据库操作,三个子线程执行查询数据库对象, writethread = new SQLWritethread("write",true,sqLiteUtil);writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil);
readThread_three = new SQLReadThread("three",true,sqLiteUtil);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
03-17 16:33:56.580 28028-28076/com.example.zth.seven V/zzw: write update 03-17 16:33:56.582 28028-28078/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male 03-17 16:33:56.582 28028-28078/com.example.zth.seven V/zzw: one query 03-17 16:33:56.595 28028-28077/com.example.zth.seven V/zzw: write_two update 03-17 16:33:56.596 28028-28079/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male 03-17 16:33:56.597 28028-28079/com.example.zth.seven V/zzw: two query 03-17 16:33:56.598 28028-28080/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male 03-17 16:33:56.598 28028-28080/com.example.zth.seven V/zzw: three query 03-17 16:33:56.601 28028-28076/com.example.zth.seven V/zzw: write update 03-17 16:33:56.602 28028-28078/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:10 性别:male 03-17 16:33:56.602 28028-28078/com.example.zth.seven V/zzw: one query 03-17 16:33:56.605 28028-28077/com.example.zth.seven V/zzw: write_two update 03-17 16:33:56.606 28028-28079/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:10 性别:male 03-17 16:33:56.607 28028-28079/com.example.zth.seven V/zzw: two query 03-17 16:33:56.609 28028-28080/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:10 性别:male 03-17 16:33:56.609 28028-28080/com.example.zth.seven V/zzw: three query
可以看出同一个SQLiteDataBase对象多线程读写操作没问题
第二种情况,两个SQLiteDataBase对象不同线程
一个子线程执行update函数,所持有的SQLiteDataBase对象是sqLiteUtil,而其他三个子线程执行query函数,所持有的SQLiteDataBase对象是sqLiteUtil_two,writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil_two);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
因为无限循环的时候没有设置sleep,模仿多次读写操作,所以log很多重复的
03-17 16:39:16.634 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.634 29175-29295/com.example.zth.seven V/zzw: one query
03-17 16:39:16.636 29175-29296/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.638 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:16.640 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
03-17 16:39:16.640 29175-29297/com.example.zth.seven V/zzw: three query
03-17 16:39:16.642 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:0 性别:male
。。。。。。
03-17 16:39:16.650 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:16.665 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.668 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.975 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.977 29175-29294/com.example.zth.seven V/zzw: write update
03-17 16:39:16.980 29175-29294/com.example.zth.seven V/zzw: write update
。。。。。。。。。。
03-17 16:39:17.081 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.081 29175-29297/com.example.zth.seven V/zzw: three query
03-17 16:39:17.083 29175-29295/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.083 29175-29295/com.example.zth.seven V/zzw: one query
03-17 16:39:17.083 29175-29296/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
03-17 16:39:17.084 29175-29296/com.example.zth.seven V/zzw: two query
03-17 16:39:17.085 29175-29297/com.example.zth.seven V/zzw: query------->姓名:xiaoming 年龄:1060 性别:male
。。。。。。。。。。。
运行正常
两个个子线程执行update函数,所持有的SQLiteDataBase对象是sqLiteUtil,而其他三个子线程执行query函数,所持有的SQLiteDataBase对象是sqLiteUtil_two,
writethread = new SQLWritethread("write",true,sqLiteUtil);
writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil_two);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
一开始几秒还好,然后就说子线程执行的query函数有问题
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (Sqlite code 5), (OS error - 2:No such file or directory)
看来在不同线程下读操作不能在多个SQLiteDataBase对象进行写操作的时候来完成
如果是读操作那边有两个SQLiteDataBase对象呢 writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
// writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
结果一样
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (Sqlite code 14), (OS error - 24:Too many open files)
结论:在不同的线程完成读写操作只能使用同一个SQLiteDataBase对象,或者写操作使用一个SQLiteDataBase对象,读操作使用一个SQLiteDataBase对象
代码:public class SQLiteActivity extends Activity {
/** Called when the activity is first created. */
//声明各个按钮
private Button createBtn;
private Button insertBtn;
private Button updateBtn;
private Button queryBtn;
private Button deleteBtn;
private Button ModifyBtn,btn_thread_start,btn_thread_stop;
private SQLiteUtil sqLiteUtil,sqLiteUtil_two;
private SQLWritethread writethread,writethread_two;
private SQLReadThread readThread_one;
private SQLReadThread readThread_two;
private SQLReadThread readThread_three;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_five);
//调用creatView方法
creatView();
//setListener方法
setListener();
}
//通过findViewById获得Button对象的方法
private void creatView(){
createBtn = (Button)findViewById(R.id.createDatabase);
updateBtn = (Button)findViewById(R.id.updateDatabase);
insertBtn = (Button)findViewById(R.id.insert);
ModifyBtn = (Button)findViewById(R.id.update);
queryBtn = (Button)findViewById(R.id.query);
deleteBtn = (Button)findViewById(R.id.delete);
btn_thread_start = (Button)findViewById(R.id.btn_thread_start);
btn_thread_stop = (Button)findViewById(R.id.btn_thread_stop);
}
//为按钮注册监听的方法
private void setListener(){
createBtn.setOnClickListener(new CreateListener());
updateBtn.setOnClickListener(new UpdateListener());
insertBtn.setOnClickListener(new InsertListener());
ModifyBtn.setOnClickListener(new ModifyListener());
queryBtn.setOnClickListener(new QueryListener());
deleteBtn.setOnClickListener(new DeleteListener());
btn_thread_start.setOnClickListener(new ThreadStartListener());
btn_thread_stop.setOnClickListener(new ThreadStopListener());
sqLiteUtil = new SQLiteUtil(this);
sqLiteUtil_two = new SQLiteUtil(this);
}
//创建数据库的方法
class CreateListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.initSQL();
}
}
//升级数据库的方法
class UpdateListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.upgradeSQL();
}
}
//插入数据的方法
class InsertListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.insertSQL();
}
}
//查询数据的方法
class QueryListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.querySQL();
}
}
//修改数据的方法
class ModifyListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.updateSQL();
}
}
//删除数据的方法
class DeleteListener implements OnClickListener{
@Override
public void onClick(View v) {
sqLiteUtil.deleteSQL();
}
}
class ThreadStartListener implements OnClickListener{
@Override
public void onClick(View v) {
writethread = new SQLWritethread("write",true,sqLiteUtil);
//writethread_two = new SQLWritethread("write_two",true,sqLiteUtil);
readThread_one = new SQLReadThread("one",true,sqLiteUtil);
readThread_two = new SQLReadThread("two",true,sqLiteUtil_two);
readThread_three = new SQLReadThread("three",true,sqLiteUtil_two);
writethread.start();
// writethread_two.start();
readThread_one.start();
readThread_two.start();
readThread_three.start();
}
}
class ThreadStopListener implements OnClickListener{
@Override
public void onClick(View v) {
writethread.setState(false);
// writethread_two.setState(false);
readThread_one.setState(false);
readThread_two.setState(false);
readThread_three.setState(false);
}
}
@Override
protected void onDestroy() {
writethread.setState(false);
// writethread_two.setState(false);
readThread_one.setState(false);
readThread_two.setState(false);
readThread_three.setState(false);
sqLiteUtil_two.closeSQL();
sqLiteUtil.closeSQL();
super.onDestroy();
}
}
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="hello" /> <Button android:id="@+id/createDatabase" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="创建数据库" /> <Button android:id="@+id/updateDatabase" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="更新数据库" /> <Button android:id="@+id/insert" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="插入数据" /> <Button android:id="@+id/update" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="更新数据" /> <Button android:id="@+id/query" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="查询数据" /> <Button android:id="@+id/delete" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="删除数据" /> <Button android:id="@+id/btn_thread_start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="开启多线程" /> <Button android:id="@+id/btn_thread_stop" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="停止多线程" /> </LinearLayout>
public class SQLiteUtil { private Context context; private SQLiteDatabase db; public SQLiteUtil(Context context){ this.context = context; StuDBHelper dbHelper = new StuDBHelper(context,"stu_db",null,1); //得到一个可写的数据库 db =dbHelper.getReadableDatabase(); } public void closeSQL(){ if(db != null&& db.isOpen()){ db.close(); } } public void initSQL(){ //创建StuDBHelper对象 StuDBHelper dbHelper = new StuDBHelper(context,"stu_db",null,1); //得到一个可读的SQLiteDatabase对象 SQLiteDatabase db =dbHelper.getReadableDatabase(); } public void upgradeSQL(){ // 数据库版本的更新,由原来的1变为2 StuDBHelper dbHelper = new StuDBHelper(context,"stu_db",null,2); SQLiteDatabase db =dbHelper.getReadableDatabase(); } public void deleteSQL(){ db.beginTransaction(); //手动设置开始事务 try{ //批量处理操作 String whereClauses = "id=?"; String [] whereArgs = {String.valueOf(1)}; //调用delete方法,删除数据 db.delete("stu_table", whereClauses, whereArgs); db.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交 }catch(Exception e){ }finally{ db.endTransaction(); //处理完成 } } public void insertSQL(){ db.beginTransaction(); //手动设置开始事务 try{ //批量处理操作 //生成ContentValues对象 //key:列名,value:想插入的值 ContentValues cv = new ContentValues(); //往ContentValues对象存放数据,键-值对模式 cv.put("id", 1); cv.put("sname", "xiaoming"); cv.put("sage", 21); cv.put("ssex", "male"); //调用insert方法,将数据插入数据库 db.insert("stu_table", null, cv); db.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交 }catch(Exception e){ }finally{ db.endTransaction(); //处理完成 } } public void updateSQL(){ db.beginTransaction(); //手动设置开始事务 try{ //批量处理操作 ContentValues cv = new ContentValues(); cv.put("sage", "23"); //where 子句 "?"是占位符号,对应后面的"1", String whereClause="id=?"; String [] whereArgs = {String.valueOf(1)}; //参数1 是要更新的表名 //参数2 是一个ContentValeus对象 //参数3 是where子句 db.update("stu_table", cv, whereClause, whereArgs); db.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交 }catch(Exception e){ }finally{ db.endTransaction(); //处理完成 } } public void updateSQL(int sum){ db.beginTransaction(); //手动设置开始事务 try{ //批量处理操作 ContentValues cv = new ContentValues(); cv.put("sage", ""+sum); //where 子句 "?"是占位符号,对应后面的"1", String whereClause="id=?"; String [] whereArgs = {String.valueOf(1)}; //参数1 是要更新的表名 //参数2 是一个ContentValeus对象 //参数3 是where子句 db.update("stu_table", cv, whereClause, whereArgs); db.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交 }catch(Exception e){ }finally{ db.endTransaction(); //处理完成 } } public void querySQL(){ //参数1:表名 //参数2:要想显示的列 //参数3:where子句 //参数4:where子句对应的条件值 //参数5:分组方式 //参数6:having条件 //参数7:排序方式 db.beginTransaction(); //手动设置开始事务 try{ //批量处理操作 Cursor cursor = db.query("stu_table", new String[]{"id","sname","sage","ssex"}, "id=?", new String[]{"1"}, null, null, null); while(cursor.moveToNext()){ String name = cursor.getString(cursor.getColumnIndex("sname")); String age = cursor.getString(cursor.getColumnIndex("sage")); String sex = cursor.getString(cursor.getColumnIndex("ssex")); Log.v("zzw","query------->" + "姓名:"+name+" "+"年龄:"+age+" "+"性别:"+sex); } db.setTransactionSuccessful(); //设置事务处理成功,不设置会自动回滚不提交 }catch(Exception e){ }finally{ db.endTransaction(); //处理完成 } } }
public class SQLReadThread extends Thread { private boolean state = true; private SQLiteUtil sqLiteUtil; public void setState(boolean state){ this.state = state; } public SQLReadThread(String name,boolean state,SQLiteUtil sqLiteUtil) { super(name); this.state = state; this.sqLiteUtil = sqLiteUtil; } @Override public void run() { for (int i = 0;state; i++) { sqLiteUtil.querySQL(); Log.v("zzw",getName()+" query"); } } }
public class SQLWritethread extends Thread { private boolean state = true; private SQLiteUtil sqLiteUtil; public void setState(boolean state){ this.state = state; } public SQLWritethread(String name,boolean state,SQLiteUtil sqLiteUtil) { super(name); this.state = state; this.sqLiteUtil = sqLiteUtil; } @Override public void run() { for (int i = 0;state; i++) { if(getName().equals("write_two")) sqLiteUtil.updateSQL(i*10); else sqLiteUtil.updateSQL(i*10); Log.v("zzw",getName()+" update"); } } }
public class StuDBHelper extends SQLiteOpenHelper { private static final String TAG = "TestSQLite"; public static final int VERSION = 1; //必须要有构造函数 public StuDBHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } // 当第一次创建数据库的时候,调用该方法 @Override public void onCreate(SQLiteDatabase db) { String sql = "create table stu_table(id int,sname varchar(20),sage int,ssex varchar(10))"; //输出创建数据库的日志信息 Log.i(TAG, "create Database------------->"); //execSQL函数用于执行SQL语句 db.execSQL(sql); } //当更新数据库的时候执行该方法 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //输出更新数据库的日志信息 Log.i(TAG, "update Database------------->"); } }
题外话:你是不是觉得我应该使用getWriteableDataBase,但我可以负责的告诉你基本两种函数得到的SQLiteDatabase对象都能进行读写操作,只会在存储空间不够的情况下才有点区别。(ps:我的64G大存储可能吗)
SQLite线程同步源码分析
加点东西,看了点源码分析了一下SQLite如何完成线程同步,我的切入点就是SQLite如何自己实现的线程同步我们首先分析读操作也就是query命令如何实现线程同步,跟着我command加鼠标左键看源码
首先query方法里又放了一个query,很正常,加默认参数,(ps:源码在SQLiteDatabase类)
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
}
还是加默认参数,(ps:源码在SQLiteDatabase类) public Cursor query(boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, null);
}
到了真正实现query方法的源码了(ps:源码在SQLiteDatabase类)
public Cursor queryWithFactory(CursorFactory cursorFactory,
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
acquireReference();
try {
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
findEditTable(table), cancellationSignal);
} finally {
releaseReference();
}
}
看到了acquireReference()和releaseReference(),不是感觉很可疑,不要急,我们再看看rawQueryWithFactory方法的源码(ps:源码在SQLiteDatabase类)
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}
又看到了这个两个函数,但是我们还要看看driver.query源码(ps:源码在SQLiteCursorDriver类)
Cursor query(CursorFactory factory, String[] bindArgs);
没了,只是个接口函数,好了我们再来看看acquireReference()和releaseReference()的源码,(ps:源码在SQLiteClosable类)
public void acquireReference() {
synchronized(this) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
"attempt to re-open an already-closed object: " + this);
}
mReferenceCount++;
}
}
public void releaseReference() {
boolean refCountIsZero = false;
synchronized(this) {
refCountIsZero = --mReferenceCount == 0;
}
if (refCountIsZero) {
onAllReferencesReleased();
}
}
感觉是通过Synchronized同步锁锁住自己,来完成线程同步,因为SQLiteDatabase是这个抽象类SQLiteClosable的子类,还不能做判断,再看看onAllReferencesReleased()源码
protected abstract void onAllReferencesReleased();
抽象函数,。。。。。。没关系,看看SQLiteDatabase如何实现这个抽象函数
@Override
protected void onAllReferencesReleased() {
dispose(false);
}
private void dispose(boolean finalized) {
final SQLiteConnectionPool pool;
synchronized (mLock) {
if (mCloseGuardLocked != null) {
if (finalized) {
mCloseGuardLocked.warnIfOpen();
}
mCloseGuardLocked.close();
}
pool = mConnectionPoolLocked;
mConnectionPoolLocked = null;
}
if (!finalized) {
synchronized (sActiveDatabases) {
sActiveDatabases.remove(this);
}
if (pool != null) {
pool.close();
}
}
}
又是同步锁,来防止同时执行多次close(),源码就看到这里,我们再看看官方说明,(PS:百度翻译的)
acquireReference()
获取对对象的引用。
close()
释放一个对对象的引用,如果最后一个引用被释放,则关闭对象。
releaseReference()
释放一个对对象的引用,如果最后一个引用被释放,则关闭对象。
但是这里我们注意一下mReferenceCount的默认值为1
private int mReferenceCount = 1;
acquireReference()和releaseReference()时是成双成对的出现,一个加,一个减,除非我们调用一次close,否则他不会关闭对象的
结论:SQLiteDatabase通过同步锁锁自己的对象来完成在多线程下读写线程同步,并且通过控制mReferenceCount来中断读写操作,因为锁住的是对象所以对于不同对象的SQLiteDatabase对同一个数据库文件的过频繁或同时的打开就会导致错误
相关文章推荐
- android sqlite多线程读写分析与优化
- Android进阶——多线程系列之异步任务AsyncTask的使用与源码分析
- Android多线程相关知识总结——源码分析
- Android多线程之AsyncTask源码分析
- android 多线程数据库读写分析与优化(转)
- 开源中国 OsChina Android 客户端源码分析(8)数据库Sqlite
- android 多线程数据库读写分析与优化【转】
- SQLiteDatabase 多线程数据库读写分析与优化
- Mavlink地面站编写之五—MP源码多线程读写框架分析
- 我之见--java多线程之可重入锁,读写锁源码分析 及自定义锁AQS
- android 多线程数据库读写分析与优化
- Android多线程基础之从Looper源码深度分析
- Android多线程(二)AsyncTask源码分析
- Android多线程(三)AsyncTask源码分析(Android7.0)
- android 多线程数据库读写分析与优化
- Android 多线程:AsyncTask的原理 及其源码分析
- Mavlink地面站编写之六---MP源码多线程读写框架分析
- Android多线程(二)AsyncTask源码分析
- Android多线程消息处理机制(三) Handler部分源码分析
- android 多线程数据库读写分析与优化