Semaphore的介绍别的博客都有,原理方法什么的, 但是没有封装的,这个主要是讲如何封装的,想要去学习原理的话,去别的博客吧。
首先粘贴代码,工具封装类
/**
* Created by EDZ on 2021/7/23.
* Describe:Semaphore封装类
*/
public class Test implements Runnable {
private static CountDownLatch latch = new CountDownLatch(1);
//信号量,第一个为可用钥匙数量,第二个为是否公平模式,公平模式为按顺序执行,不公平模式自己抢
//需要用volatile修饰,test本身需要成为全局工具,避免反复创建Semaphore,不然会失效
private static volatile Semaphore semaphore = new Semaphore(1, true);
//用来执行的接口
private static TestInterface testInterface;
public void run() {
try {
//启动线程池调用
latch.await();
this.work();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//执行信号量取钥匙操作
private void work() {
try {
//查询是否有空余的钥匙可以使用, 有返回true,没有返回false
//第一个为申请钥匙数量,第二个为超时时间,第三个是超时单位
//需要注意,返回true的时候,tryAcquire本身就会持有钥匙,不需要在调用acquire
boolean b = semaphore.tryAcquire(1,5, TimeUnit.SECONDS);
if (b==true){
if (testInterface!=null){
testInterface.setThread();
}else {
semaphore.release();
}
}else {
//执行失败的处理,可以同样用接口回调, 我的处理方式是舍弃
}
} catch (InterruptedException e) {
e.printStackTrace();
LogUtil.e("子线程 失败:");
}
}
//信号封锁执行完毕,释放钥匙
public void setNum() {
LogUtil.e("子线程结束:");
semaphore.release();
}
//添加新的锁来尝试获取钥匙
public void setTest(TestInterface test) {
LogUtil.e("子线程添加:");
testInterface = test;
Thread t = new Thread(new Test());
t.start();
//保证所有线程同时运行
latch.countDown();
}
//回传的接口,根据需求自己随便改
public interface TestInterface {
void setThread();
}
}
这就是封装好了,为了避免工具类反复创建,造成信号锁重复申请创建,可以直接在
Application中初始化,作为全局使用, 如果需要多个不互相影响的锁,就多创建几个实例就可以
public class MyApp extends Application {
public static Test test;
public static Test getTest(){
return test;
}
@Override
public void onCreate() {
super.onCreate();
test=new Test();
}
}
接下来是在项目中使用
/**
* Created by EDZ on 2021/7/16.
* Describe:信号量调用类
*/
public class XinhaoliangActivity extends AppCompatActivity implements View.OnClickListener
{
Button bt_a, bt_b;
Test test;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xinhaoliang);
//注册监听
EventBus.getDefault().register(this);
bt_a = findViewById(R.id.bt_a);
bt_b = findViewById(R.id.bt_b);
bt_a.setOnClickListener(this);
bt_b.setOnClickListener(this);
test=MyApp.getTest();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_a:
test.setTest(new Test.TestInterface() {
@Override
public void setThread() {
//模拟延时操作的子线程,这里也是处理获取钥匙后的业务逻辑
ThreadUtils threadUtils = new ThreadUtils(XinhaoliangActivity.this);
threadUtils.start();
}
});
break;
case R.id.bt_b:
test.setTest(new Test.TestInterface() {
@Override
public void setThread() {
//简单的跳转,过去之后记得将信号释放
Intent intent=new Intent(XinhaoliangActivity.this,MainActivity.class);
startActivity(intent);
}
});
break;
}
}
//接收订阅TestEvent事件的执行函数,当接收到发布者发布的TestEvent事件后会被调用
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageBean event) {
// LogUtil.e("子线程结束:");
test.setNum();
}
}
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/bt_a"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A"
/>
<Button
android:id="@+id/bt_b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="b"
/>
</LinearLayout>
跳转类
public class MainActivity extends AppCompatActivity {
private File temp;
Test test;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test=MyApp.getTest();
test.setNum();//释放信号量的钥匙
}
}
子线程延时模拟类
public class ThreadUtils extends Thread implements XinInterface.Presenter {
Context mContext;
volatile int item = 0;
public ThreadUtils(Context context ) {
this.mContext = context;
}
@Override
public void run() {
super.run();
while (true) {
try {
sleep(1000);
item++;
LogUtil.e("子线程:" + " " + item);
if (item ==10) {
EventBus.getDefault().post(
new MessageBean(0,"",""));
item=0;
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
eventbus传值类
public class MessageBean {
private int code;
private String message;
private String data;
public MessageBean(int code, String message, String data) {
this.code = code;
this.message = message;
this.data = data;
}
public void setCode(int code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
public void setData(String data) {
this.data = data;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getData() {
return data;
}
@Override
public String toString() {
return "MessageBean{" +
"code=" + code +
", message='" + message + '\'' +
", data='" + data + '\'' +
'}';
}
}
好了,整个信号量的封装就完成了,看不懂的,上面的全沾到项目里,让XinhaoliangActivity作为默认启动类就可以了
|