原创

Java-synchronized-Lock-锁-加锁-并发插入重复数据-service层加锁要注意


并发插入重复数据说明:

接口并发的地方加个锁,单实例亲测有效, 多实例 使用分布式锁。
(应该发现一次就必须加,核心的代码底层也应该加)。
尤其是在同一个方法内判断新增还是编辑的逻辑,insertOrUpdate方法必须加(并发插入重复数据几乎必现)。
如果接口调用service,service有事务,synchronized加在service方法上,可能导致加锁失败,有可能是因为事务提交间隔的原因,解决方法是把锁加载controller层【最新,也不一定是在service层加锁导致失败,后续还要观察】

package cn.jiangjiesheng.edu.controller.backend.train;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

private static int countBySynchronized = 0;
private static int countByLock = 0;
private static final int targetTotal = 20;

//TODO 复制
// Lock的用法(写的比较好) https://blog.csdn.net/weixin_40583386/article/details/86170355 (原文 https://www.cnblogs.com/aishangJava/p/6555291.html
// synchronized和Lock的区别是什么? https://www.php.cn/java/base/464183.html
// 5分钟搞清楚Synchronized和Lock的概念与区别https://blog.51cto.com/u_14442094/2435026
public static void main(String[] args) {
LockTest lockTest = new LockTest();
Thread t1 = new Thread(new Runnable1(lockTest));
Thread t2 = new Thread(new Runnable2(lockTest));
t1.start();
t2.start();

}

static class Runnable1 implements Runnable {
LockTest lockTest = null;

Runnable1(LockTest lockTest) {
this.lockTest = lockTest;
}

@Override
public void run() {
for (int i = 0; i < targetTotal / 2; i++) {
lockTest.doAddBySynchronized();
lockTest.doAddByLock();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1.countBySynchronized = " + countBySynchronized + ",thread1.countByLock = " + countByLock + ",期望两个线程处理的总和为:" + targetTotal);
}
}

static class Runnable2 implements Runnable {
LockTest lockTest = null;

Runnable2(LockTest lockTest) {
this.lockTest = lockTest;
}

@Override
public void run() {
for (int i = 0; i < targetTotal / 2; i++) {
lockTest.doAddBySynchronized();
lockTest.doAddByLock();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread2.countBySynchronized = " + countBySynchronized + ",thread2.countByLock = " + countByLock + ",期望两个线程处理的总和为:" + targetTotal);
}
}

private final static Object synchronizedLock = new Object();

private void doAddBySynchronized() {//synchronized 1
// synchronized (this) { 2
//countBySynchronized++;
// }
synchronized (synchronizedLock) { //3
countBySynchronized++;
}
// 以上3种都有效果
}

//进入Lock类,定位,看jar中的实现类
private Lock lock = new ReentrantLock(); // 这个不能doAddByLock() 方法内,何时初始化?难道用private final static修饰(属于整个类,不用创建对象)

//https://blog.csdn.net/weixin_40583386/article/details/86170355
//lock() tryLock() lockInterruptibly() ,另外关注读写锁
private void doAddByLock() {
//tryLock()用法,不一定会拿到锁
// if (lock.tryLock()) {
// try {
// //处理任务
// countByLock++;
// } catch (Exception ex) {
// System.out.println("处理任务出现异常" + ex);
// } finally {
// lock.unlock(); //释放锁
// }
// } else {
// //如果不能获取锁,则直接做其他事情
// System.out.println("未获取到锁");
// }

//lock() 会等待,需要catch后释放锁
lock.lock();
try {
//处理任务
countByLock++;
} catch (Exception ex) {
System.out.println("处理任务出现异常" + ex);
} finally {
lock.unlock(); //释放锁
}
}
}


Connected to the target VM, address: '127.0.0.1:55092', transport: 'socket'
thread1.countBySynchronized = 20,thread1.countByLock = 20,期望两个线程处理的总和为:20
thread2.countBySynchronized = 20,thread2.countByLock = 20,期望两个线程处理的总和为:20
Disconnected from the target VM, address: '127.0.0.1:55092', transport: 'socket'

Process finished with exit code 0

正文到此结束
本文目录