func (idMutex *idMutexImpl) UnlockID(identifier interface{}) {
	shard := idMutex.shards[idMutex.getShardIndex(identifier)]
	shard.Lock()
	mutexInfo, ok := shard.mutexInfos[identifier]
	if !ok {
		panic("cannot find workflow lock")
	}
	mutexInfo.Unlock()
	if mutexInfo.waitCount == 1 {
		delete(shard.mutexInfos, identifier)
	} else {
		mutexInfo.waitCount--
	}
	shard.Unlock()
}
UnlockID unlock by specific identifier
package locks
import (
	"sync"
)
type (
	HashFunc func(interface{}) uint32
	IDMutex interface {
		LockID(identifier interface{})
		UnlockID(identifier interface{})
	}
	idMutexImpl struct {
		numShard uint32
		hashFn   HashFunc
		shards   map[uint32]*idMutexShardImpl
	}
	idMutexShardImpl struct {
		sync.Mutex
		mutexInfos map[interface{}]*mutexInfo
	}
	mutexInfo struct {
		waitCount int
		sync.Mutex
	}
)
func NewIDMutex(numShard uint32, hashFn HashFunc) IDMutex {
	impl := &idMutexImpl{
		numShard: numShard,
		hashFn:   hashFn,
		shards:   make(map[uint32]*idMutexShardImpl),
	}
	for i := uint32(0); i < numShard; i++ {
		impl.shards[i] = &idMutexShardImpl{
			mutexInfos: make(map[interface{}]*mutexInfo),
		}
	}
	return impl
}
func newMutexInfo() *mutexInfo {
	return &mutexInfo{
		waitCount: 1,
	}
}
func (idMutex *idMutexImpl) LockID(identifier interface{}) {
	shard := idMutex.shards[idMutex.getShardIndex(identifier)]
	shard.Lock()
	mutexInfo, ok := shard.mutexInfos[identifier]
	if !ok {
		mutexInfo := newMutexInfo()
		shard.mutexInfos[identifier] = mutexInfo
		shard.Unlock()
		mutexInfo.Lock()
		return
	}
	mutexInfo.waitCount++
	shard.Unlock()
	mutexInfo.Lock()
}