日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

图文|Android 使用Thread 和多线程使用互斥锁

發布時間:2023/12/20 Android 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图文|Android 使用Thread 和多线程使用互斥锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么需要多線程進行開發?

多線程不管是嵌入式系統RTOS,Linux,還是應用開發,中間件開發,都是必不可少的,做一個技術的時候,如果能做到舉一反三,下次使用的時候不會再遇到坑,我這次給出的例子是Android 的多線程開發。


如何使用一個線程

在Android 應用程序里面如何使用一個線程呢?直接看下面的代碼,代碼不是很多,如果需要用的話直接摘抄過去就好了。

//定義一個線程
private?SendThread?mSendThread?=?null;

/**
?*?線程實體
?*/

private?class?SendThread?extends?Thread{

????public?void?run()?{
????}
}

//實例化線程
if?(mSendThread?==?null){
???mSendThread?=?new?SendThread();
}

//啟動線程
mSendThread.start();

多次調用start是同一個堆??臻g嗎?

如果只new了一次線程,多次start,會出現怎么樣的情況呢?

android 線程start的函數原型如下

public?synchronized?void?start()?{
????????/**
?????????*?This?method?is?not?invoked?for?the?main?method?thread?or?"system"
?????????*?group?threads?created/set?up?by?the?VM.?Any?new?functionality?added
?????????*?to?this?method?in?the?future?may?have?to?also?be?added?to?the?VM.
?????????*
?????????*?A?zero?status?value?corresponds?to?state?"NEW".
?????????*/

????????//?Android-changed:?throw?if?'started'?is?true
????????if?(threadStatus?!=?0?||?started)
????????????throw?new?IllegalThreadStateException();

????????/*?Notify?the?group?that?this?thread?is?about?to?be?started
?????????*?so?that?it?can?be?added?to?the?group's?list?of?threads
?????????*?and?the?group's?unstarted?count?can?be?decremented.?*/

????????group.add(this);

????????started?=?false;
????????try?{
????????????nativeCreate(this,?stackSize,?daemon);
????????????started?=?true;
????????}?finally?{
????????????try?{
????????????????if?(!started)?{
????????????????????group.threadStartFailed(this);
????????????????}
????????????}?catch?(Throwable?ignore)?{
????????????????/*?do?nothing.?If?start0?threw?a?Throwable?then
??????????????????it?will?be?passed?up?the?call?stack?*/

????????????}
????????}
????????}

然后我做了下面的一個代碼實驗

/**
?*?發送線程實體
?*/

private?class?SendThread?extends?Thread{
????int?testCount?=?20;

????public?void?run()?{
????????while(testCount?>0)
????????{
????????????Log.d(TAG,"testCount:"+testCount);
????????????testCount?--;
????????}
????}
}

//實例化線程
if?(mSendThread?==?null){
???mSendThread?=?new?SendThread();
}

//啟動線程
mSendThread.start();
mSendThread.start();

結果輸出如下

D/ttyusb:?testCount:20
D/ttyusb:?testCount:20
D/ttyusb:?testCount:19
D/ttyusb:?testCount:19
D/ttyusb:?testCount:18
D/ttyusb:?testCount:18
D/ttyusb:?testCount:17
D/ttyusb:?testCount:16
D/ttyusb:?testCount:17
D/ttyusb:?testCount:15
D/ttyusb:?testCount:16
D/ttyusb:?testCount:14
D/ttyusb:?testCount:15
D/ttyusb:?testCount:13
D/ttyusb:?testCount:14
D/ttyusb:?testCount:12
D/ttyusb:?testCount:13
D/ttyusb:?testCount:11
D/ttyusb:?testCount:12
D/ttyusb:?testCount:10
D/ttyusb:?testCount:9
D/ttyusb:?testCount:11
D/ttyusb:?testCount:8
D/ttyusb:?testCount:10
D/ttyusb:?testCount:7
D/ttyusb:?testCount:9
D/ttyusb:?testCount:6
D/ttyusb:?testCount:5
D/ttyusb:?testCount:8
D/ttyusb:?testCount:4
D/ttyusb:?testCount:7
D/ttyusb:?testCount:3
D/ttyusb:?testCount:6
D/ttyusb:?testCount:2
D/ttyusb:?testCount:1
D/ttyusb:?testCount:5
D/ttyusb:?testCount:4
D/ttyusb:?testCount:3
D/ttyusb:?testCount:2
D/ttyusb:?testCount:1

可以看出線程每次start后,他們使用的堆??臻g是不相同的。

在雙線程里面使用互斥鎖

使用互斥鎖的情況非常普遍,但是新手寫代碼肯定會有道意想不到的問題,我就是那個新手,我就遇到了那個意想不到的問題。

給出下面一段代碼

/**
?????*?線程實體
?????*/

????public?class?SendThread?extends?Thread?{


????????public?void?run()?{
????????????isStart?=?true;
????????????for(int?i=0;i<20;i++)
????????????{
????????????????lock.lock();
????????????????successCount?=?i;
????????????????lock.unlock();
????????????????Log.d(TAG,?"Write:testCount:"?+?successCount);
????????????}
????????????isStart?=?false;
????????}
????}

????/**
?????*?接收數據的線程
?????*/

????public?class?ReceiveThread?extends?Thread?{

????????@Override
????????public?void?run()?{

????????????int?testCount?=?20;

????????????super.run();
????????????//條件判斷,只要條件為true,則一直執行這個線程
????????????while?(isStart?==?true)?{

????????????????testCount?=?successCount;

????????????????Log.d(TAG,?"Read:testCount:"?+?testCount);
????????????}

????????}
????}

代碼執行的流程大概如下


代碼輸出


03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:0
03-08?11:41:35.383?14866-14866/??D/TEST:?啟動線程完成
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:1
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:2
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:1
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:3
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:3
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:4
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:4
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:5
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:5
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:6
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:6
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:7
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:7
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:8
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:8
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:9
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:9
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:10
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:10
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:11
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:11
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:12
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:12
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:13
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:13
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:14
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:14
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:15
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:15
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:16
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:16
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:17
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:17
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:18
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:18
03-08?11:41:35.383?14866-14906/??D/TEST:?Write:testCount:19
03-08?11:41:35.383?14866-14907/??D/TEST:?Read:testCount:19

上述代碼問題

我們希望的代碼流程是,我發送一個數據,你就接收一個數據,不能出現數據丟失的情況,但是上面的日子來看,接收數據是發生了丟失,這樣的情況如果在實際應用中是非常危險的。

所以代碼需要類似下面這樣修改

????/**
?????*?線程實體
?????*/

????public?class?SendThread?extends?Thread?{


????????public?void?run()?{
????????????isStart?=?true;
????????????for(int?i=0;i<20;i++)
????????????{
????????????????Log.d(TAG,"開始寫線程~");
????????????????lock.lock();
????????????????successCount?=?i;
????????????????Log.d(TAG,?"寫數據:testCount:"?+?successCount);
????????????????lock.unlock();
????????????????Log.d(TAG,"寫線程休眠~");
????????????????sendTreadSleep(10);
????????????}
????????????isStart?=?false;
????????}
????}

????/**
?????*?接收數據的線程
?????*/

????public?class?ReceiveThread?extends?Thread?{

????????@Override
????????public?void?run()?
{

????????????int?testCount?=?20;

????????????super.run();
????????????//條件判斷,只要條件為true,則一直執行這個線程
????????????while?(isStart?==?true)?{
????????????????Log.d(TAG,"開始讀線程~");
????????????????lock.lock();
????????????????testCount?=?successCount;
????????????????Log.d(TAG,?"讀數據~:testCount:"?+?testCount);
????????????????lock.unlock();
????????????????Log.d(TAG,"讀線程休眠~");
????????????????receiveTreadSleep(5);
????????????}

????????}
????}

工程的Demo到時候在文末給出,寫線程在寫完后,就休眠10MS,然后再到讀線程執行,加的日志非常方便大家觀看兩個線程之間的運行邏輯。

日志輸出如下

?D/TEST:?啟動線程完成
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:0
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:0
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:0
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:1
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:1
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:1
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:2
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:2
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:2
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:3
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:3
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?開始讀線程~
?D/TEST:?寫數據:testCount:4
?D/TEST:?寫線程休眠~
?D/TEST:?讀數據~:testCount:4
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:4
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:5
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:5
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:5
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:6
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:6
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:6
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:7
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:7
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:7
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:8
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:8
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:8
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:9
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:9
?D/TEST:?讀線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:9
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:10
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:10
?D/TEST:?讀線程休眠~
grande.ttyusb.test0001/com.evergrande.ttyusb.test0001.MainActivity]?connect:?already?connected?(cur=1?req=1)
?D/TEST:?開始讀線程~
?D/TEST:?開始寫線程~
?D/TEST:?讀數據~:testCount:10
?D/TEST:?讀線程休眠~
?D/TEST:?寫數據:testCount:11
?D/TEST:?寫線程休眠~
?D/mali_winsys:?EGLint?new_window_surface(egl_winsys_display*,?void*,?EGLSurface,?EGLConfig,?egl_winsys_surface**,?egl_color_buffer_format*,?EGLBoolean)?returns?0x3000
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:11
?D/TEST:?讀線程休眠~
?D/TEST:?開始寫線程~
?D/TEST:?寫數據:testCount:12
?D/TEST:?寫線程休眠~
?D/TEST:?開始讀線程~
?D/TEST:?讀數據~:testCount:12

使用synchronized來達到完成互斥

synchronized修飾的方法可以讓兩個方法之間完成互斥,比如寫和讀互斥,寫和寫互斥,讀和讀互斥,都可以用這個方法。
使用代碼如下

??/**
?????*?線程實體
?????*/

????public?class?SendThread?extends?Thread?{


????????public?void?run()?{
????????????isStart?=?true;
????????????for(int?i=0;i<10;i++)
????????????{
????????????????Log.d(TAG,"開始寫線程~");
????????????????mDataValue.setData(i);
????????????????Log.d(TAG,?"寫數據:testCount:"?+?successCount);
????????????????Log.d(TAG,"寫線程休眠~");
????????????????sendTreadSleep(10);
????????????}
????????????isStart?=?false;
????????}
????}

????/**
?????*?接收數據的線程
?????*/

????public?class?ReceiveThread?extends?Thread?{

????????@Override
????????public?void?run()?{

????????????int?testCount?=?20;
????????????Log.d(TAG,"s開始讀線程~");
????????????super.run();
????????????//條件判斷,只要條件為true,則一直執行這個線程
????????????while?(isStart?==?true)?{
????????????????Log.d(TAG,"開始讀線程~");
????????????????testCount?=?mDataValue.getData();
????????????????Log.d(TAG,?"讀數據~:testCount:"?+?testCount);
????????????????Log.d(TAG,"讀線程休眠~");
????????????????receiveTreadSleep(5);
????????????}
????????}
????}

????/**
?????*?發送線程延遲
?????*?@param?millis?毫秒
?????*/

????private?void?sendTreadSleep(int?millis)
????
{
????????try{
????????????mSendThread.sleep(millis);
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????}
????/**
?????*?接收線程延遲
?????*?@param?millis?毫秒
?????*/

????private?void?receiveTreadSleep(int?millis)
????
{
????????try{
????????????mReceiveThread.sleep(millis);
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????}

????private?class?DataValue{

????????private?synchronized?void?setData(int?value){
????????????Log.d(TAG,"設置數據~setData");
????????????successCount?=?value;
????????}

????????private?synchronized??int?getData(){
????????????Log.d(TAG,"獲取數據~getData");
????????????return?successCount;
????????}

????}

讀寫鎖ReentrantReadWriteLock

上面是使用互斥鎖,這里介紹一個讀寫鎖,也是用來完成互斥的。使用代碼如下

????/**
?????*?線程實體
?????*/

????public?class?SendThread?extends?Thread?{


????????public?void?run()?{
????????????isStart?=?true;
????????????for(int?i=0;i<10;i++)
????????????{
????????????????mrwDataValue.setData(i);
????????????????Log.d(TAG,Thread.currentThread().getName()?+"寫休眠");
????????????????sendTreadSleep(10);
????????????}
????????????isStart?=?false;
????????}
????}

????/**
?????*?接收數據的線程
?????*/

????public?class?ReceiveThread?extends?Thread?{

????????@Override
????????public?void?run()?
{

????????????int?testCount?=?20;
????????????Log.d(TAG,"s開始讀線程~");
????????????super.run();
????????????//條件判斷,只要條件為true,則一直執行這個線程
????????????while?(isStart?==?true)?{
????????????????mrwDataValue.getData();
????????????????Log.d(TAG,Thread.currentThread().getName()?+"讀休眠");
????????????????receiveTreadSleep(5);
????????????}
????????}
????}
????/*
?????*?使用讀寫鎖完成互斥ReadWriteLock
?????*/

????private?class?rwDataValue{
????????private?ReadWriteLock?readWriteLock?=?new?ReentrantReadWriteLock();
????????private?int?Data;

????????private?void?setData(int?value){
????????????readWriteLock.writeLock().lock();
????????????try?{
????????????????Log.d(TAG,?Thread.currentThread().getName()?+"寫數據~setData:"+value);
????????????????Data?=?value;
????????????????Thread.sleep(30);
????????????}catch?(Exception?i){
????????????????Log.e(TAG,"error");
????????????}finally?{
????????????????readWriteLock.writeLock().unlock();
????????????}
????????}

????????private??void?getData(){
????????????readWriteLock.readLock().lock();
????????????try?{
????????????????Log.d(TAG,Thread.currentThread().getName()?+"獲取數據~getData:"?+Data);
????????????????Thread.sleep(10);
????????????}catch?(Exception?i){
????????????????Log.e(TAG,"error");
????????????}finally?{
????????????????readWriteLock.readLock().unlock();
????????????}
????????}



參考

https://blog.csdn.net/zy_style/article/details/53423877

Demo 代碼

https://github.com/weiqifa0/androitdThread



當你看到這里的時候,說明你已經閱讀完上面的內容

不管怎樣,感謝您有心或者無意的關注和支持

想獲取學習1024G資料,請點擊狀態欄公眾號福利按鈕





總結

以上是生活随笔為你收集整理的图文|Android 使用Thread 和多线程使用互斥锁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。