Mutex与Semaphore的区别

本文探讨了Mutex(互斥锁)和Semaphore(信号量)在Android编程中的区别与使用场景,通过实例展示了它们如何确保代码串行执行和资源限制。重点讲解了在不同情况下的选择与对比,以及在订阅服务和绑定远程服务过程中的应用。
摘要由CSDN通过智能技术生成

Mutex 的发音是 /mjuteks/ ,其含义为互斥(体),这个词是Mutual Exclude的缩写。
Mutex在计算机中是互斥也就是排他持有的一种方式,和信号量-Semaphore有可以对比之处。有人做过如下类比:
Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。一般的用法是用于串行化对critical section代码的访问,保证这段代码不会被并行的运行。

Semaphore 是一件可以容纳N人的房间,如果人不满就可以进去,如果人满了,就要等待有人出来。对于N=1的情况,称为binary semaphore。一般的用法是,用于限制对于某一资源的同时访问。

对于Binary semaphore与Mutex,这两者之间就存在了很多相似之处:

  • 在有的系统中Binary semaphore与Mutex是没有差异的。
  • 在有的系统上,主要的差异是mutex一定要由获得锁的进程来释放。而semaphore可以由其它进程释放(这时的semaphore实际就是个原子的变量,大家可以加或减),因此semaphore可以用于进程间同步。
  • Semaphore的同步功能是所有系统都支持的,而Mutex能否由其他进程释放则未定,因此建议mutex只用于保护critical section。而semaphore则用于保护某变量,或者同步。

示例一

public class ServiceObservable extends Maybe<RemoteServiceInterface> {
    private static final Semaphore SEMAPHORE = new Semaphore(1, true);
    private static volatile RemoteServiceInterface mServiceInterface = null;

    public static ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(4);
    private ServiceConnection mServiceConnection;

    public ServiceObservable() {
    }

    @RequiresApi(api = Build.VERSION_CODES.R)
    @Override
    protected void subscribeActual(MaybeObserver<? super RemoteServiceInterface> observer) {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            throw new RuntimeException("not allow on main thread !!!");
        }

        Timber.d("subscribeActual thread -> %s", Thread.currentThread().getName());

        observer.onSubscribe(new Disposable() {
            private final AtomicBoolean mUnsubscribed = new AtomicBoolean();

            @Override
            public void dispose() {
                if (mUnsubscribed.compareAndSet(false, true)) {
                    Timber.d("unbindService ...");
                    if (mServiceConnection != null) {
                        Utils.getApp().unbindService(mServiceConnection);
                    }
                    mServiceInterface = null;
                }
            }

            @Override
            public boolean isDisposed() {
                return mUnsubscribed.get();
            }
        });

        if (mServiceInterface == null || !mServiceInterface.asBinder().isBinderAlive() ){
            try {
                SEMAPHORE.acquire();
            } catch (InterruptedException e) {
                observer.onError(e);
            }
        }

        if (mServiceInterface != null && mServiceInterface.asBinder().isBinderAlive()) {
            observer.onSuccess(mServiceInterface);
            observer.onComplete();
        } else {
            mServiceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    Timber.d("onServiceConnected thread -> %s...", Thread.currentThread().getName());

                    mServiceInterface = RemoteServiceInterface.Stub.asInterface(service);

                    SEMAPHORE.release();

//                        Timber.d("onServiceConnected object -> %s", mServiceInterface.toString());

                    observer.onSuccess(mServiceInterface);
                    observer.onComplete();
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                    Timber.d("onServiceDisconnected ...");
                    mServiceInterface = null;
                }
            };

            Intent intent = new Intent();
            intent.setAction("com.ehome.service.RemoteService");
            intent.setPackage("com.ehome.connect.sample");


            boolean success = Utils.getApp().bindService(intent, Context.BIND_AUTO_CREATE, EXECUTOR_SERVICE, mServiceConnection);

            if (!success) {
                observer.onError(new RuntimeException("bindService failed !!!"));
            }
        }
    }
}

示例二

    Intent intent = new Intent();
        intent.setAction("com.ehome.service.RemoteService");
        intent.setPackage("com.ehome.connect.sample");

        try {
            SEMAPHORE.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Timber.d("onServiceConnected ...");
                SEMAPHORE.release();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };

        Timber.d("bindService ...");
        boolean success = Utils.getApp().bindService(intent, Context.BIND_AUTO_CREATE, EXECUTOR_SERVICE,serviceConnection);

        Timber.d("after bindService ...");

        try {
            SEMAPHORE.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        SEMAPHORE.release();

        Timber.d("end ...");

示例三

package com.ehome.connect.sample;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;

import com.blankj.utilcode.util.Utils;

import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;

import io.reactivex.Maybe;
import io.reactivex.MaybeObserver;
import io.reactivex.disposables.Disposable;
import timber.log.Timber;

public class ServiceObservable extends Maybe<RemoteServiceInterface> {
    private static final Semaphore SEMAPHORE = new Semaphore(1, true);

    private static volatile RemoteServiceInterface mServiceInterface = null;

    private ServiceConnection mServiceConnection;

    public ServiceObservable() {
    }

    @Override
    protected void subscribeActual(MaybeObserver<? super RemoteServiceInterface> observer) {
        Timber.d("subscribeActual thread -> %s ...", Thread.currentThread().getName());

        observer.onSubscribe(new Disposable() {
            private final AtomicBoolean mUnsubscribed = new AtomicBoolean();

            @Override
            public void dispose() {
                Timber.d("dispose ...");
                if (mUnsubscribed.compareAndSet(false, true)) {
                    Timber.d("unbindService ...");
                    if (mServiceConnection != null) {
                        Utils.getApp().unbindService(mServiceConnection);
                    }
                    mServiceInterface = null;
                }
            }

            @Override
            public boolean isDisposed() {
                return mUnsubscribed.get();
            }
        });

        if (mServiceInterface == null || !mServiceInterface.asBinder().isBinderAlive()) {
            synchronized (ServiceObservable.class) {
                if (mServiceInterface == null || !mServiceInterface.asBinder().isBinderAlive()) {
                    try {
                        Timber.d("before first acquire  ...");
                        SEMAPHORE.acquire();
                    } catch (InterruptedException e) {
                        observer.onError(e);
                        return;
                    }

                    mServiceConnection = new ServiceConnection() {
                        @Override
                        public void onServiceConnected(ComponentName name, IBinder service) {
                            Timber.d("onServiceConnected thread -> %s ...", Thread.currentThread().getName());
                            mServiceInterface = RemoteServiceInterface.Stub.asInterface(service);

                            Timber.d("before first release  ...");
                            SEMAPHORE.release();
                        }

                        @Override
                        public void onServiceDisconnected(ComponentName name) {
                            Timber.d("onServiceDisconnected ...");
                            mServiceInterface = null;
                        }
                    };

                    Intent intent = new Intent();
                    intent.setAction("com.ehome.service.RemoteService");
                    intent.setPackage("com.ehome.connect.sample");

                    Timber.d("before bindService thread -> %s ...", Thread.currentThread().getName());

                    boolean success = Utils.getApp().bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

                    Timber.d("before second acquire thread -> %s ...", Thread.currentThread().getName());
                    try {
                        SEMAPHORE.acquire();
                    } catch (InterruptedException e) {
                        observer.onError(e);
                        return;
                    }

                    Timber.d("before second release thread -> %s ...", Thread.currentThread().getName());
                    SEMAPHORE.release();

                    if (!success) {
                        observer.onError(new RuntimeException("bindService failed !!!"));
                        return;
                    }
                }
            }
        }

        Timber.d("before onSuccess thread -> %s ...", Thread.currentThread().getName());
        observer.onSuccess(mServiceInterface);
        observer.onComplete();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值