java - 简单的 Java 代码允许单线程访问和其他线程跳过/继续

标签 java multithreading concurrency synchronization semaphore

换句话说,我不希望线程在无法访问锁时等待(如在同步中),我希望线程执行在无法获得锁时立即立即返回。

像这样简单的 boolean 锁可能会允许多个线程访问。

private static boolean lockAvailable = true;

private boolean acquireLock() {
  if(lockAvailable) {
    lockAvailable = false;
    return true;
  }
  return false;
}

我错过了什么吗?实现此目标的最佳/最简单方法是什么?

编辑:

感谢您指出信号量 (!)

所以再看一遍这段代码是防弹的?

private final static Semaphore lock = new Semaphore(1, true);   

public void tryAndDoSomething() {
  if(lock.tryAcquire()) {
    try {
      // only single thread can access here at one time
    } finally {
      lock.release();
    }
  }
}

更新:

我意识到我需要可重入功能,所以我创建了一个简单的非阻塞可重入功能。为任何对您如何执行此操作感兴趣的人发布代码。任何想要这种功能的人当然应该使用 existing Java 类 java.util.concurrent.locks.ReentrantLock :|

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

/**
 * SimpleNonBlockingLock ensures that only a single thread can call protected code at any one time,
 * while allowing other threads to by pass the protected code if the lock is unavailable.
 * The thread owning the lock can access any code protected by the lock (the lock is 'reentrant').
 * To function correctly the protected code must be executed in a try/finally blocks. The
 * finally block must call the tryRelease. Example code:
 * 
 *  private final SimpleNonBlockingLock lock = new SimpleNonBlockingLock();
 * 
 *  if(lock.tryAcquire()) {
 *      try {
 *              // access protected code
 *      } finally {
 *          lock.tryRelease();
 *      }
 *  }
 *
 * This code is for demonstration only and should not be used. I have tested it and it 'seems to' work.
 * However it may contain horrific bugs!
 * 
 * The Java class java.util.concurrent.locks.ReentrantLock has been around since Java 5.0 and contains all (and more) 
 * of this functionality. Its also been thoroughly tested!
 */
public class SimpleNonBlockingLock {

    // Atomic locking mechanism
    private final AtomicBoolean locked = new AtomicBoolean();

    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Unique ID of thread which currently has lock
    private int threadUniqueId = -1;

    // Tracks number of tryAcquire calls made by thread with lock
    private int lockCount = 0;

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
            @Override protected Integer initialValue() {
                return nextId.getAndIncrement();
        }
    };

    public synchronized boolean tryAcquire() {      
        // Allow owning thread to acquire
        if(threadUniqueId == getCurrentThreadUniqueId()) {
            lockCount++;
            return true;
        }       
        // If locked then do not allow
        if (locked.get()) {return false;}           
        // Attempt to acquire lock      
        boolean attemptAcquire = locked.compareAndSet(false, true);     
        // If successful then set threadUniqueId for the thread, and increment lock count
        if(attemptAcquire) {
            threadUniqueId = getCurrentThreadUniqueId();
            lockCount++;
        }       
        // Return result of attempt to acquire lock
        return attemptAcquire;
    }

    public synchronized boolean tryRelease() {
        if (!locked.get()) {
            // Lock is currently available - no need to try and release
            return true;
        } else {
            // Decrement the lock count
            lockCount--;
            // If lock count is zero we release lock, and reset the threadUniqueId
            if(lockCount == 0) {
                threadUniqueId = -1;
                return locked.compareAndSet(true, false);
            } 
            return false;
        }   
    }

    // Returns the current thread's unique ID, assigning it if necessary
    public static int getCurrentThreadUniqueId() {      
        return threadId.get();
    }   
}

最佳答案

Java 5 引入了 explicit locks有一个 tryLock手术。所以使用显式锁而不是同步块(synchronized block),然后你可以调用tryLock:

private Lock lock = ...;

private boolean acquireLock() {
  if (lock.tryLock()) {
      ...
      return true;
  } else {
      return false;
  }
}

关于java - 简单的 Java 代码允许单线程访问和其他线程跳过/继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7359005/

相关文章:

c++ - ReleaseSemaphore 不释放信号量

Java CPU 使用率应该是 100%...但它不是

Java 互斥

java - 维护线程池任务队列的类型信息

java - 使用 eclipse 插件在 GAE 上部署应用程序

java - 线程对象的run方法

适用于 Windows Server 的 ServiceBus 上的 Java - 选项?

java - Netty服务器关闭第二个客户端连接

Java ArrayList - 不设置现有元素

java - 如何让 Jackson 使用 Google Guice Injector 创建实例?