信号量,了解过操作系统的人都知道,信号量是用来做什么的···
在Android中,已经提供了Semaphore来帮助我们使用~
那么,在开发中这家伙有什么用呢?
用的地方不多,但是却真的是好用至极!
#0 举个栗子
我相信很多人在开发中都会遇到这样的事情:当要对一个资源进行多次数据读取并且修改操作时,会遇到执行的速度快慢不一致导致修改值发生改变的情况。
比如如下代码:
1 private void Start() { 2 for (int i = 10; i >= 0; i--) { 3 LogString = "num:" + i; 4 printLogString(i); 5 } 6 } 7 8 private void printLogString(final int delayTime) { 9 Log.e("TAG", "Runnable" + delayTime); 10 new Thread(new Runnable() { 11 @Override 12 public void run() { 13 Log.e("TAG", LogString); 14 } 15 }).start(); 16 }
打印出的日志会不一致,如:
04-03 15:33:07.294 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable10 04-03 15:33:07.296 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable9 04-03 15:33:07.296 17078-17777/com.gao.luna.semaphoretest E/TAG: num:9 04-03 15:33:07.297 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable8 04-03 15:33:07.297 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable7 04-03 15:33:07.298 17078-17778/com.gao.luna.semaphoretest E/TAG: num:7 04-03 15:33:07.299 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable6 04-03 15:33:07.299 17078-17779/com.gao.luna.semaphoretest E/TAG: num:6 04-03 15:33:07.300 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable5 04-03 15:33:07.301 17078-17780/com.gao.luna.semaphoretest E/TAG: num:5 04-03 15:33:07.301 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable4 04-03 15:33:07.302 17078-17781/com.gao.luna.semaphoretest E/TAG: num:4 04-03 15:33:07.303 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable3 04-03 15:33:07.303 17078-17782/com.gao.luna.semaphoretest E/TAG: num:3 04-03 15:33:07.304 17078-17783/com.gao.luna.semaphoretest E/TAG: num:3 04-03 15:33:07.305 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable2 04-03 15:33:07.305 17078-17784/com.gao.luna.semaphoretest E/TAG: num:2 04-03 15:33:07.305 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable1 04-03 15:33:07.306 17078-17078/com.gao.luna.semaphoretest E/TAG: Runnable0 04-03 15:33:07.306 17078-17785/com.gao.luna.semaphoretest E/TAG: num:0 04-03 15:33:07.308 17078-17786/com.gao.luna.semaphoretest E/TAG: num:0 04-03 15:33:07.308 17078-17787/com.gao.luna.semaphoretest E/TAG: num:0
这和我们希望见到的num从10打印到0时不相符的。
#1 Semaphore的使用
接着上面的代码,我们加入Semaphore来解决这个问题:
1 private final Semaphore semaphore = new Semaphore(0, true);
这里有个坑需要注意一下,比如说这个队列限制只有1个存在,那么在创建时要写0,写1的话,就会变成2个了···以此类推,要队列中有10个对象,需要写9···
在每次acquire后,semaphone将加入一个对象,在不release的情况下,这个对象是会一直存在的。
下面上代码:
1 private final Semaphore semaphore = new Semaphore(0, true); 2 3 private void Start() { 4 for (int i = 10; i >= 0; i--) { 5 try { 6 Log.e("Semaphore", "semaphore.acquire();" + i); 7 semaphore.acquire(); 8 } catch (Exception ex) { 9 Log.e("Semaphore", ex.getMessage()); 10 } 11 LogString = "num:" + i; 12 printLogString(i); 13 } 14 } 15 16 private void printLogString(final int delayTime) { 17 new Thread(new Runnable() { 18 @Override 19 public void run() { 20 Log.e("Semaphore", "semaphore.release();"); 21 Log.e("TAG", LogString); 22 semaphore.release(); 23 } 24 }).start(); 25 }
日志如下:
04-03 15:40:41.060 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.065 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();10 04-03 15:40:41.078 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();9 04-03 15:40:41.078 26200-26513/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.084 26200-26513/com.gao.luna.semaphoretest E/TAG: num:10 04-03 15:40:41.086 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();8 04-03 15:40:41.086 26200-26514/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.086 26200-26514/com.gao.luna.semaphoretest E/TAG: num:9 04-03 15:40:41.086 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();7 04-03 15:40:41.087 26200-26515/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.087 26200-26515/com.gao.luna.semaphoretest E/TAG: num:8 04-03 15:40:41.087 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();6 04-03 15:40:41.088 26200-26516/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.088 26200-26516/com.gao.luna.semaphoretest E/TAG: num:7 04-03 15:40:41.088 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();5 04-03 15:40:41.088 26200-26517/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.088 26200-26517/com.gao.luna.semaphoretest E/TAG: num:6 04-03 15:40:41.089 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();4 04-03 15:40:41.089 26200-26518/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.089 26200-26518/com.gao.luna.semaphoretest E/TAG: num:5 04-03 15:40:41.090 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();3 04-03 15:40:41.090 26200-26519/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.091 26200-26519/com.gao.luna.semaphoretest E/TAG: num:4 04-03 15:40:41.091 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();2 04-03 15:40:41.092 26200-26520/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.092 26200-26520/com.gao.luna.semaphoretest E/TAG: num:3 04-03 15:40:41.092 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();1 04-03 15:40:41.093 26200-26521/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.093 26200-26521/com.gao.luna.semaphoretest E/TAG: num:2 04-03 15:40:41.094 26200-26200/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();0 04-03 15:40:41.094 26200-26522/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.094 26200-26522/com.gao.luna.semaphoretest E/TAG: num:1 04-03 15:40:41.095 26200-26523/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 15:40:41.095 26200-26523/com.gao.luna.semaphoretest E/TAG: num:0
这里我们可以很清晰的看到,num从10顺序变为了0。
#2 再加点延迟试试
现在,我们再在其中增加一些sleep代码,再来测试看看。
1 private final Semaphore semaphore = new Semaphore(0, true); 2 3 private void Start() { 4 for (int i = 10; i >= 0; i--) { 5 try { 6 Log.e("Semaphore", "semaphore.acquire();" + i); 7 semaphore.acquire(); 8 } catch (Exception ex) { 9 Log.e("Semaphore", ex.getMessage()); 10 } 11 LogString = "num:" + i; 12 printLogString(i); 13 } 14 } 15 16 private void printLogString(final int delayTime) { 17 Log.e("TAG", "Runnable" + delayTime); 18 new Thread(new Runnable() { 19 @Override 20 public void run() { 21 try { 22 Thread.sleep(delayTime * 10); 23 } catch (Exception ex) { 24 Log.e("delayTime", ex.getMessage()); 25 } 26 Log.e("Semaphore", "semaphore.release();"); 27 Log.e("TAG", LogString); 28 semaphore.release(); 29 } 30 }).start(); 31 }
然后看看日志:
04-03 16:15:34.028 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.028 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();10 04-03 16:15:34.028 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable10 04-03 16:15:34.029 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();9 04-03 16:15:34.129 18148-18230/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.129 18148-18230/com.gao.luna.semaphoretest E/TAG: num:10 04-03 16:15:34.130 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable9 04-03 16:15:34.130 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();8 04-03 16:15:34.221 18148-18232/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.221 18148-18232/com.gao.luna.semaphoretest E/TAG: num:9 04-03 16:15:34.221 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable8 04-03 16:15:34.222 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();7 04-03 16:15:34.302 18148-18245/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.302 18148-18245/com.gao.luna.semaphoretest E/TAG: num:8 04-03 16:15:34.303 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable7 04-03 16:15:34.382 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();6 04-03 16:15:34.453 18148-18251/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.453 18148-18251/com.gao.luna.semaphoretest E/TAG: num:7 04-03 16:15:34.453 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable6 04-03 16:15:34.462 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();5 04-03 16:15:34.523 18148-18266/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.523 18148-18266/com.gao.luna.semaphoretest E/TAG: num:6 04-03 16:15:34.523 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable5 04-03 16:15:34.529 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();4 04-03 16:15:34.579 18148-18267/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.579 18148-18267/com.gao.luna.semaphoretest E/TAG: num:5 04-03 16:15:34.579 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable4 04-03 16:15:34.635 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();3 04-03 16:15:34.675 18148-18268/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.675 18148-18268/com.gao.luna.semaphoretest E/TAG: num:4 04-03 16:15:34.675 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable3 04-03 16:15:34.676 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();2 04-03 16:15:34.706 18148-18272/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.706 18148-18272/com.gao.luna.semaphoretest E/TAG: num:3 04-03 16:15:34.706 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable2 04-03 16:15:34.733 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();1 04-03 16:15:34.753 18148-18275/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.753 18148-18275/com.gao.luna.semaphoretest E/TAG: num:2 04-03 16:15:34.753 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable1 04-03 16:15:34.754 18148-18148/com.gao.luna.semaphoretest E/Semaphore: semaphore.acquire();0 04-03 16:15:34.764 18148-18280/com.gao.luna.semaphoretest E/Semaphore: semaphore.release(); 04-03 16:15:34.764 18148-18280/com.gao.luna.semaphoretest E/TAG: num:1 04-03 16:15:34.764 18148-18148/com.gao.luna.semaphoretest E/TAG: Runnable0 04-03 16:15:34.765 18148-18281/com.gao.luna.semaphoretest E/Semaphore: semaphore.release();
04-03 16:15:34.765 18148-18281/com.gao.luna.semaphoretest E/TAG: num:0
仍然没有问题~~~
#3 需要注意的地方
如果使用了Handler,需要注意的是,Handler会返回主线程来进行调用,如果在Handler未执行时在acquire地方暂停了,那么Handler是不会执行的。需要特别留意。
下面是全部的代码:
1 package com.gao.luna.semaphoretest; 2 3 import android.os.Bundle; 4 import android.support.design.widget.FloatingActionButton; 5 import android.support.v7.app.AppCompatActivity; 6 import android.support.v7.widget.Toolbar; 7 import android.util.Log; 8 import android.view.View; 9 10 import java.util.concurrent.Semaphore; 11 12 13 public class MainActivity extends AppCompatActivity { 14 15 private String LogString; 16 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 22 setSupportActionBar(toolbar); 23 24 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 25 fab.setOnClickListener(onClickListener); 26 } 27 28 View.OnClickListener onClickListener = new View.OnClickListener() { 29 @Override 30 public void onClick(View v) { 31 Log.e("Semaphore", "semaphore.release();"); 32 semaphore.release(); 33 Start(); 34 } 35 }; 36 37 private final Semaphore semaphore = new Semaphore(0, true); 38 39 private void Start() { 40 for (int i = 10; i >= 0; i--) { 41 try { 42 Log.e("Semaphore", "semaphore.acquire();" + i); 43 semaphore.acquire(); 44 } catch (Exception ex) { 45 Log.e("Semaphore", ex.getMessage()); 46 } 47 LogString = "num:" + i; 48 printLogString(i); 49 } 50 } 51 52 private void printLogString(final int delayTime) { 53 Log.e("TAG", "Runnable" + delayTime); 54 new Thread(new Runnable() { 55 @Override 56 public void run() { 57 try { 58 Thread.sleep(delayTime * 10); 59 } catch (Exception ex) { 60 Log.e("delayTime", ex.getMessage()); 61 } 62 Log.e("Semaphore", "semaphore.release();"); 63 Log.e("TAG", LogString); 64 semaphore.release(); 65 } 66 }).start(); 67 } 68 }