业务
系统需要把待办推送到B系统. 情况1:用了定时任务每分钟推送。 情况2:如果A系统在生成待办时调用定时任务的方法手动推送。 所以出现了多线程执行,导致方法重复执行。 使用同步锁解决问题!# 定时任务代码 @Scheduled(cron = "*/3 * * * * ?") public void ceShi() { try { log.info(Thread.currentThread().getName()); Thread.sleep(5000); } catch (Exception e) { log.error("待办portalWork表推送OA任务异常", e); } } # 普通接口 @RequestMapping("/ceShi") public void ceShi() { portalWorkTask.ceShi(); }
游览器重复调用/ceShi 接口
查看idea控制台,在方法中睡眠5秒钟重复进入方法!
private final ReentrantLock lock = new ReentrantLock(); lock.lock(); try { log.info(Thread.currentThread().getName()); Thread.sleep(5000); } catch (Exception e) { log.error("待办portalWork表推送OA任务异常", e); } finally { lock.unlock(); }
可以看到进入方法中,如果存在锁,必须等待,释放完锁后,再次进入方法!
synchronized 是和 if、else、for、while 一样的关键字,ReentrantLock 是类,这是二者的本质区别。既然 ReentrantLock 是类,那么它就提供了比synchronized 更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量
相同点:两者都是可重入锁
两者都是可重入锁。“可重入锁”概念是:自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
主要区别如下:
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
答:
公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
使用方法:
等待是否可中断:
加锁是否公平:
锁绑定多个条件Condition:
多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下:
javaclass ShareResource {
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void print5() {
lock.lock();
try {
while (number != 1) {
condition1.await();
}
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
number = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10() {
lock.lock();
try {
while (number != 2) {
condition2.await();
}
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
number = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15() {
lock.lock();
try {
while (number != 3) {
condition3.await();
}
for (int i = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
number = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class SyncAndReentrantLockDemo {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print5();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print10();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.print15();
}
}, "CCC").start();
}
}
公平锁: 多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
非公平锁: 多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
可重入锁(也叫递归锁): 线程可以进入任何一个它已经拥有的锁所同步的代码块(如:租房,门外面是一把门锁,进去之后厕所、厨房不会安装锁,直接可以用)
手写自旋锁
java
public class AtomicTest {
AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "^_^");
while (!atomicReference.compareAndSet(null, thread)) {
}
}
public void myOnLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "关闭");
atomicReference.compareAndSet(thread,null);
}
public void test(Integer i){
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
public static void main(String[] args){
AtomicTest atomicTest = new AtomicTest();
new Thread(() -> {
atomicTest.myLock();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicTest.myOnLock();
},"t1").start();
new Thread(() -> {
atomicTest.myLock();
atomicTest.myOnLock();
},"t2").start();
AtomicInteger atomicReference1 = new AtomicInteger();
AtomicInteger atomicReference2 = new AtomicInteger(5);
System.out.println(1);
}
}
自旋锁: 是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上线文切换的消耗,缺点是循环会消耗CPU
独占锁: 该锁一直只能被一个线程所持有。lock和synchronized都是独占锁
共享锁: 该锁可被多个线程所持有。读写分离。
本文作者:酷少少
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!