简单基于Oracle实现分布式锁

首先还原一个线程不安全的事故现场:

运行结果:

明显是有问题的,相同的票售出了多次。

基于Oracle实现简单的分布式锁

创建一个仅有一个主键字段的表:

数据库实体类:

@Table(name = "oracle_lock")
@Setter
@Getter
@AllArgsConstructor
public class OracleLockEntity {

    @Id
    @Column(name = "id")
    private String id;
}

Mapper接口:

/**
 * @author Dongguabai
 * @date 2018-07-20 11:01
 */
public interface OracleLockMapper extends Mapper<OracleLockEntity> {
}

Lock接口的方法太多,现在建一个中间实现类:

/**
 * @author Dongguabai
 * @date 2018-07-20 11:13
 */
public class LockDecorator implements Lock{
    @Override
    public void lock() {

    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void unlock() {

    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

编写数据库锁:

/**
 * Oracle分布式锁
 * 注意:1.性能较差
 * 2.可能会出现死锁(比如解锁的时候数据库挂了)
 * 3.代码复杂
 * 4.不可重入
 *
 * @author Dongguabai
 * @date 2018-07-20 10:56
 */
@Component("simpleOracleLock")
@Slf4j
public class SimpleOracleLock extends LockDecorator {

    public static final String LOCK_ID = "1";
    public static final OracleLockEntity LOCK_ORACLE_ENTITY = new OracleLockEntity(LOCK_ID);

    @Autowired
    private OracleLockMapper oracleLockMapper;

    /**
     * 非阻塞式加锁
     *
     * @return
     */
    @Override
    public boolean tryLock() {
        try {
            oracleLockMapper.insert(LOCK_ORACLE_ENTITY);
        } catch (Exception e) {
            log.info("尝试加锁失败!");
            return false;
        }
        return true;
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        oracleLockMapper.deleteByPrimaryKey(LOCK_ID);
    }

    /**
     * 阻塞式加锁
     */
    @Override
    public void lock() {
        if (!tryLock()) {
            int randomSleepMillis = new Random().nextInt(100);
            try {
                Thread.sleep(randomSleepMillis);
            } catch (InterruptedException e) {
                log.info("尝试加锁失败,线程sleep{}毫秒!", randomSleepMillis);
            }
            lock();
        }
    }

}

运行测试:

    @Resource(name = "simpleOracleLock")
    private Lock simpleOracleLock;

    @Test
    public void test22() throws InterruptedException {
        RunnableImpl runnable = new RunnableImpl();
        Thread t1 = new Thread(runnable, "售票窗口一");
        Thread t2 = new Thread(runnable, "售票窗口二");
        Thread t3 = new Thread(runnable, "售票窗口三");
        Thread t4 = new Thread(runnable, "售票窗口四");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        //主线程等待子线程执行完毕
        Thread.currentThread().join();
    }

    class RunnableImpl implements Runnable {

        @Override
        public void run() {
            while (sum > 0) {
                simpleOracleLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "现在卖了第" + (sum--) + "张票");
                }catch (Exception e){

                }finally {
                    simpleOracleLock.unlock();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

运行结果:

符合要求,按照顺序票一个个卖出去了。

猜你喜欢

转载自blog.csdn.net/dongguabai/article/details/81131162
今日推荐