Java行级锁实现


package com.thgy.bc.common.lock;

import lombok.*;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.*;

/**
 * RowLevelLock
 * Example:
 * <pre>
 *     try{
 *          lock(id)
 *     } finally {
 *          unlock(id)
 *     }
 * </pre>
 *
 * @author Ryan
 * @version 1.0
 * @date 2020/05/26
 */
@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RowLevelLock<K> {

    private static final int DELAY_IN_SECOND = 60;

    private final Map<K, Semaphore> map = new ConcurrentHashMap<>();

    private final DelayQueue<DelayTask> queue = new DelayQueue();

    /**
     * lock
     *
     * @param key
     */
    public void lock(@NonNull K key) {
        map.computeIfAbsent(key, (k) -> new Semaphore(1))
                .acquireUninterruptibly();
        queue.offer(new DelayTask(
                DateUtils.addSeconds(new Date(), DELAY_IN_SECOND),
                key));
    }

    /**
     * unlock
     *
     * @param key
     */
    public void unlock(@NonNull K key) {
        map.computeIfPresent(key, (k, v) -> {
            if (!v.hasQueuedThreads()) {
                map.remove(key);
                queue.remove(new DelayTask(key));
            }
            v.release();
            return v;
        });
    }

    /**
     * try with resource syntax
     *
     * @param key
     * @return
     */
    public AutoCloseable tryLock(@NonNull K key) {
        lock(key);
        return () -> {
            unlock(key);
        };
    }

    @Getter
    @RequiredArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode(of = "key")
    private class DelayTask implements Delayed, CommandLineRunner {

        private Date delayTime;

        @NonNull
        private K key;

        @Override
        public long getDelay(TimeUnit unit) {
            return delayTime.getTime() - System.currentTimeMillis();
        }

        @Override
        public int compareTo(Delayed o) {
            return delayTime.compareTo(((DelayTask) o).getDelayTime());
        }

        @Async
        @Override
        public void run(String... args) throws Exception {
            try {
                while (true) {
                    unlock(queue.take().getKey());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                //retry
                run();
            }
        }
    }

}


版权声明:本文为qq_44309610原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。