Android中的Semaphore

信号量,了解过操作系统的人都知道,信号量是用来做什么的···

在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 }

全部代码

时间: 2024-10-13 05:38:51

Android中的Semaphore的相关文章

49.Android中线程同步异步方式小结

同步和异步的区别 首先以一个常见的开发场景来区别一下同步和异步的区别,比如我们要获取一张网络图片并完成显示.在这个场景中我们需要开启两个线程,一个是子线程—即下载图片的线程:另外是主 UI 线程—即图片下载完成后进行显示的线程.针对这个场景分别用两幅实现的流程图来区分同步和异步. 从图中可以看到,二者的区别在于:同步时当前主线程会阻塞,直到子线程通知主线程为止(先不考虑ANR):而异步的时候主线程可以继续干其它的事情,当子线程完成任务的时候通知一下主线程就可以了,类似于接口回调或消息队列的思想.

谈谈-Android中的接口回调技术

Android中的接口回调技术有很多应用的场景,最常见的:Activity(人机交互的端口)的UI界面中定义了Button,点击该Button时,执行某个逻辑. 下面参见上述执行的模型,讲述James对Android接口回调技术的理解(结合前人的知识和自己的实践). 使用一个比喻很形象地说明:客户端有个疑问打电话请教服务端,但服务端无法现场给出解答,相互之间约定:服务端一旦有答案,使用电话的方式反馈给客户端. 以上有三个主体:客户端.服务端和接口(方式). 接口回调的原理框图说明: Demo界面

关于android中事件传递和分发的一些小理解

android中 当我们的手指触摸屏幕将产生一个事件, (假设 这个过程中如果没有显示的去拦截该事件的话)   这个事件会逐级传递到视图的最底层,即使在中间某些视图会响应这个事件( 这个视图也不会去消费这个事件),     仍然是会传递到底层(底层不响应该事件),然后再由底层回传到顶层,在传回顶层的过程中 ,   原先会响应该事件的视图才会去消费这个事件 例如在左图中                                 A                               

浅谈android中仅仅使用一个TextView实现高仿京东,淘宝各种倒计时

今天给大家带来的是仅仅使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.最近公司一直加班也没来得及时间去整理,今天难得休息想把这个分享给大家,只求共同学习,以及自己后续的复习.为什么会想到使用一个TextView来实现呢?因为最近公司在做一些优化的工作,其中就有一个倒计时样式,原来开发的这个控件的同事使用了多个TextView拼接在一起的,实现的代码冗余比较大,故此项目经理就说:小宏这个就交给你来优化了,并且还要保证有一定的扩展性,当时就懵逼了.不知道从何处开始

Android中监听ListView滑动到底部

Android中的应用就是ListView中向下滑动加载更多的功能,不要再onScroll方法中进行判断,那样当滑动到底部的时候,可能我们需要触发点什么事件,比如加载更多.隐藏某个控件等等. 第一种方法是直接滑动到底部就触发 listview.setOnScrollListener(new OnScrollListener(){       @Override       public void onScrollStateChanged(AbsListView view, int scrollS

Android基础入门教程——8.1.3 Android中的13种Drawable小结 Part 3

Android基础入门教程--8.1.3 Android中的13种Drawable小结 Part 3 标签(空格分隔): Android基础入门教程 本节引言: 本节我们来把剩下的四种Drawable也学完,他们分别是: LayerDrawable,TransitionDrawable,LevelListDrawable和StateListDrawable, 依旧贴下13种Drawable的导图: 1.LayerDrawable 层图形对象,包含一个Drawable数组,然后按照数组对应的顺序来

Android基础入门教程——8.1.2 Android中的13种Drawable小结 Part 2

Android基础入门教程--8.1.2 Android中的13种Drawable小结 Part 2 标签(空格分隔): Android基础入门教程 本节引言: 本节我们继续来学习Android中的Drawable资源,上一节我们学习了: ColorDrawable:NinePatchDrawable: ShapeDrawable:GradientDrawable!这四个Drawable~ 而本节我们继续来学习接下来的五个Drawable,他们分别是: BitmapDrawable:Insert

Android中微信抢红包插件原理解析和开发实现

一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导致了.或许是网络的原因,而且这个也是最大的原因.但是其他的不可忽略的因素也是要考虑到进去的,比如在手机充电锁屏的时候,我们并不知道有人已经开始发红包了,那么这时候也是让我们丧失了一大批红包的原因.那么关于网络的问题,我们开发者可能用相关技术无法解决(当然在Google和Facebook看来的话,他们

Android中View绘制流程以及invalidate()等相关方法分析

前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴望了解 Android 框架层的网友,推荐这本书,希望你们能够在Android开发里学到更多的知识 . 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measure).是否重新需要安置视图的位置(layout).以及是否需要重绘 (d