多线程环境下,会出现线程不安全的问题,所以要对某些方法加锁以保证线程安全

但是如果方法过多,每个方法前后都加这么一句,有点麻烦了,而且代码可读性也会差一些。可以使用aop切面编程,对某些加有特定注解(自定义注解)的方法做加锁操作即可。

自定义注解

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lock {
    String description() default "";
}

 

定义切面类

public class LockAspect {
    private static Lock lock = new ReentrantLock(false);//互斥锁 参数默认false,不公平锁

    /**
     * 思考:为什么不用synchronized
     * service 默认是单例的,并发下lock只有一个实例
     */
    //Service层切点     用于记录错误日志
    @Pointcut("@annotation(com.example.thread.threaddemo.Lock)")
    public void lockAspect() {
    }

    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint) {
        lock.lock();
        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return obj;
    }
}

下图中箭头处改为自己的自定义注解类的全路径,就是包名加类名

自定义注解,aop实现注解锁

 

准备测试,用售票的例子
@Service
public class Ticket1 implements Runnable {
    private int tickets = 100;

    @Override
    @Lock
    public void run() {
        while (tickets > 0) {
//            synchronized (Ticket.class) {
            if (tickets > 0) {
                tickets--;
                System.out.println(Thread.currentThread().getName() + "正在卖票,还剩下" + tickets + "张");
            }
//            }
            try {
                // 休眠一秒,让执行的效果更明显
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Ticket1 ticket = new Ticket1();
        Thread t1 = new Thread(ticket, "窗口一:");
        Thread t2 = new Thread(ticket, "窗口二:");
        Thread t3 = new Thread(ticket, "窗口三:");
        t1.start();
        t2.start();
        t3.start();
    }
}
 

 

synchronized锁的代码注释掉了,还需要在方法上加上自定义注解 @Lock

自定义注解,aop实现注解锁

 

自定义注解,aop实现注解锁

相关文章: