Java 防多线程重复保存数据
大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论一下在Java中如何防止多线程重复保存数据。在并发编程中,如果多个线程同时对同一份数据进行操作,可能会导致数据重复保存的问题。本文将通过代码示例详细介绍几种常见的解决方法,包括使用synchronized关键字、ReentrantLock、以及数据库的唯一约束等。
1. 使用synchronized关键字
synchronized关键字是Java中最简单的同步机制,它可以确保同一时刻只有一个线程可以执行某段代码。下面是一个使用synchronized关键字防止多线程重复保存数据的示例。
package cn.juwatech.threads;
import java.util.HashSet;
import java.util.Set;
public class SynchronizedSaveTask implements Runnable {
private static final Set<String> savedData = new HashSet<>();
private final String data;
public SynchronizedSaveTask(String data) {
this.data = data;
}
@Override
public void run() {
saveData(data);
}
private synchronized void saveData(String data) {
if (!savedData.contains(data)) {
savedData.add(data);
System.out.println("Thread " + Thread.currentThread().getName() + " saved data: " + data);
// 这里可以添加实际的数据保存逻辑,例如保存到数据库
} else {
System.out.println("Thread " + Thread.currentThread().getName() + " data already saved: " + data);
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new SynchronizedSaveTask("data" + (i % 5))).start();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
2. 使用ReentrantLock
ReentrantLock提供了与synchronized类似的功能,但它更加灵活,可以手动控制锁的获取和释放。下面是一个使用ReentrantLock防止多线程重复保存数据的示例。
package cn.juwatech.threads;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockSaveTask implements Runnable {
private static final Set<String> savedData = new HashSet<>();
private static final Lock lock = new ReentrantLock();
private final String data;
public LockSaveTask(String data) {
this.data = data;
}
@Override
public void run() {
saveData(data);
}
private void saveData(String data) {
lock.lock();
try {
if (!savedData.contains(data)) {
savedData.add(data);
System.out.println("Thread " + Thread.currentThread().getName() + " saved data: " + data);
// 这里可以添加实际的数据保存逻辑,例如保存到数据库
} else {
System.out.println("Thread " + Thread.currentThread().getName() + " data already saved: " + data);
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new LockSaveTask("data" + (i % 5))).start();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
3. 使用ConcurrentHashMap
ConcurrentHashMap是线程安全的Map实现,可以使用它来存储已经保存过的数据,防止重复保存。下面是一个使用ConcurrentHashMap防止多线程重复保存数据的示例。
package cn.juwatech.threads;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ConcurrentMapSaveTask implements Runnable {
private static final ConcurrentMap<String, Boolean> savedData = new ConcurrentHashMap<>();
private final String data;
public ConcurrentMapSaveTask(String data) {
this.data = data;
}
@Override
public void run() {
saveData(data);
}
private void saveData(String data) {
if (savedData.putIfAbsent(data, Boolean.TRUE) == null) {
System.out.println("Thread " + Thread.currentThread().getName() + " saved data: " + data);
// 这里可以添加实际的数据保存逻辑,例如保存到数据库
} else {
System.out.println("Thread " + Thread.currentThread().getName() + " data already saved: " + data);
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new ConcurrentMapSaveTask("data" + (i % 5))).start();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
4. 数据库的唯一约束
除了在Java代码中进行同步控制,还可以利用数据库的唯一约束来防止重复保存数据。在数据库表中对需要唯一的数据字段添加唯一约束,当插入重复数据时,数据库会抛出异常。
假设我们有一个保存用户信息的表users
,其中email
字段必须唯一:
在Java代码中处理数据库插入异常:
package cn.juwatech.threads;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DatabaseSaveTask implements Runnable {
private final String name;
private final String email;
public DatabaseSaveTask(String name, String email) {
this.name = name;
this.email = email;
}
@Override
public void run() {
saveData(name, email);
}
private void saveData(String name, String email) {
String url = "jdbc:mysql://localhost:3306/your_database";
String username = "your_username";
String password = "your_password";
try (Connection connection = DriverManager.getConnection(url, username, password)) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, name);
statement.setString(2, email);
statement.executeUpdate();
System.out.println("Thread " + Thread.currentThread().getName() + " saved data: " + email);
}
} catch (SQLException e) {
if (e.getErrorCode() == 1062) { // Duplicate entry error code for MySQL
System.out.println("Thread " + Thread.currentThread().getName() + " data already saved: " + email);
} else {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new DatabaseSaveTask("User" + (i % 5), "user" + (i % 5) + "@example.com")).start();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
通过这些方法,我们可以有效防止多线程重复保存数据,确保数据的一致性和完整性。
微赚淘客系统3.0小编出品,必属精品,转载请注明出处!