All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.maxifier.mxcache.clean.SuperLock Maven / Gradle / Ivy

Go to download

Constains all classes necessary for launching a MxCache-instrumentated application

There is a newer version: 2.6.9
Show newest version
/*
 * Copyright (c) 2008-2014 Maxifier Ltd. All Rights Reserved.
 */
package com.maxifier.mxcache.clean;

import com.maxifier.mxcache.LightweightLock;
import com.maxifier.mxcache.util.TIdentityHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.locks.Lock;

/**
 * SuperLock is a lock that wraps over few usual locks and locks them simultaneously.
 * 

* It implements a special locking algorithm that should prevents most common deadlocks, though it * may lead to starvation. *

* The algorithm is as follows:

*
    *
  • go sequentially through the underlying locks;
  • *
  • when end of array is reached, start from the beginning again;
  • *
  • try to acquire current lock with tryLock();
  • *
  • if lock is held by another thread: *
      *
    • release all previously acquired locks
    • *
    • acquire current lock with lock();
    • *
    *
  • if not all locks are acquired yet go to start;
  • *
* * @author Alexander Kochurov ([email protected]) (2014-03-31 11:17) */ public class SuperLock { private static final Logger logger = LoggerFactory.getLogger(SuperLock.class); /** masterLock is used to guard the whole SuperLock */ private final LightweightLock masterLock; private final Lock[] locks; /** * Always holds the number of locked elements. Locks are rearranged in a way that only first n * elements from locks are locked. */ private int n; public SuperLock(Collection locks) { this(locks.toArray(new Lock[locks.size()])); } public SuperLock(Lock[] locks) { this.locks = locks; masterLock = new LightweightLock(); } protected void finalize() throws Throwable { // if there was some problems, notify a user about the problem if (n != 0) { logger.error("MxCache hasn't released {} locks: {}", n, Arrays.toString(locks)); } super.finalize(); } public void lock() { masterLock.lock(); int i = 0; int firstLockedIndex = 0; int locked = 0; if (n != 0) { throw new IllegalMonitorStateException("SuperLock already locked"); } while (locked < locks.length) { Lock lock = locks[i]; if (!lock.tryLock()) { for (; locked > 0; locked--) { locks[firstLockedIndex++].unlock(); if (firstLockedIndex == locks.length) { firstLockedIndex = 0; } } lock.lock(); } locked++; i++; if (i == locks.length) { i = 0; } } n = locks.length; } public void unlock() { if (n > 0) { for (int i = 0; i < n; i++) { locks[i].unlock(); } n = 0; } masterLock.unlock(); } /** * This method allows to unlocks a part of locks. * * @throws IllegalMonitorStateException if this lock hasn't been previously locked with {@link #lock()} * @throws java.lang.IllegalArgumentException if some of locks passed don't belong to this lock or were already * unlocked. */ public void unlockPartially(TIdentityHashSet locksToRelease) { if (!masterLock.isHeldByCurrentThread()) { throw new IllegalMonitorStateException("Lock must be held by current thread"); } int to = 0; for (int i = 0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy