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();
}
}