以下將詳細說明幾種常見的Java分布式鎖解決方案,并提供具體的實現示例。
1. 基于Redis的分布式鎖
實現原理
- 使用Redis的SET命令的NX(僅當key不存在時設置)和EX(設置過期時間)選項來實現鎖的獲取。
- 使用DEL命令來釋放鎖。
示例代碼
import redis.clients.jedis.Jedis;
 ?
 public class RedisDistributedLock {
     private Jedis jedis;
     private String lockKey;
     private int expireTime; // 鎖的過期時間,單位:秒
 ?
     public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
         this.jedis = jedis;
         this.lockKey = lockKey;
         this.expireTime = expireTime;
     }
 ?
     public boolean tryLock() {
         String result = jedis.set(lockKey, "locked", "NX", "EX", expireTime);
         return "OK".equals(result);
     }
 ?
     public void unlock() {
         jedis.del(lockKey);
     }
 }
 ?
 // 使用示例
 public class Example {
     public static void main(String[] args) {
         Jedis jedis = new Jedis("localhost", 6379);
         RedisDistributedLock lock = new RedisDistributedLock(jedis, "my_lock", 10);
 ?
         if (lock.tryLock()) {
             try {
                 // 執行臨界區代碼
                 System.out.println("執行臨界區代碼");
             } finally {
                 lock.unlock();
             }
         } else {
             System.out.println("無法獲取鎖");
         }
     }
 }
2. 基于Zookeeper的分布式鎖
實現原理
- 在Zookeeper中創建一個順序節點。
- 獲取當前節點的前驅節點,如果前驅節點是父節點,則當前節點獲得鎖。
示例代碼
import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.ZooDefs.Ids;
 ?
 import java.util.List;
 ?
 public class ZookeeperDistributedLock implements Watcher {
     private ZooKeeper zookeeper;
     private String lockPath;
     private String nodePath;
     private String myNodeName;
 ?
     public ZookeeperDistributedLock(ZooKeeper zookeeper, String lockPath) {
         this.zookeeper = zookeeper;
         this.lockPath = lockPath;
     }
 ?
     public boolean tryLock() throws Exception {
         myNodeName = zookeeper.create(lockPath + "/lock-", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
         List<String> children = zookeeper.getChildren(lockPath, this);
         if (children.isEmpty()) {
             return true;
         }
         String firstChild = children.get(0);
         if (myNodeName.endsWith(firstChild)) {
             return true;
         }
         return false;
     }
 ?
     public void unlock() throws Exception {
         zookeeper.delete(nodePath, -1);
     }
 ?
     @Override
     public void process(WatchedEvent event) {
         // 監聽事件處理
     }
 }
 ?
 // 使用示例
 public class Example {
     public static void main(String[] args) throws Exception {
         ZooKeeper zookeeper = new ZooKeeper("localhost:2181", 5000, new ZookeeperDistributedLock(zookeeper, "/locks"));
         ZookeeperDistributedLock lock = new ZookeeperDistributedLock(zookeeper, "/locks");
 ?
         if (lock.tryLock()) {
             try {
                 // 執行臨界區代碼
                 System.out.println("執行臨界區代碼");
             } finally {
                 lock.unlock();
             }
         } else {
             System.out.println("無法獲取鎖");
         }
     }
 }
3. 使用數據庫實現分布式鎖
實現原理
- 在數據庫中創建一個鎖表,使用SELECT ... FOR UPDATE來獲取鎖。
- 使用UPDATE來釋放鎖。
示例代碼
import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 ?
 public class DatabaseDistributedLock {
     private Connection connection;
     private String tableName = "distributed_lock";
 ?
     public DatabaseDistributedLock(String url, String username, String password) throws Exception {
         connection = DriverManager.getConnection(url, username, password);
     }
 ?
     public boolean tryLock(String lockName) throws Exception {
         String sql = "SELECT * FROM " + tableName + " WHERE lock_name = ? FOR UPDATE";
         PreparedStatement statement = connection.prepareStatement(sql);
         statement.setString(1, lockName);
         ResultSet rs = statement.executeQuery();
 ?
         if (!rs.next()) {
             String insertSql = "INSERT INTO " + tableName + "(lock_name) VALUES (?)";
             PreparedStatement insertStatement = connection.prepareStatement(insertSql);
             insertStatement.setString(1, lockName);
             int rows = insertStatement.executeUpdate();
             return rows > 0;
         }
 ?
         return false;
     }
 ?
     public void unlock(String lockName) throws Exception {
         String sql = "DELETE FROM " + tableName + " WHERE lock_name = ?";
         PreparedStatement statement = connection.prepareStatement(sql);
         statement.setString(1, lockName);
         statement.executeUpdate();
     }
 }
 ?
 // 使用示例
 public class Example {
     public static void main(String[] args) {
         try {
             DatabaseDistributedLock lock = new DatabaseDistributedLock("jdbc:mysql://localhost:3306/mydb", "root", "password");
 ?
             if (lock.tryLock("my_lock")) {
                 try {
                     // 執行臨界區代碼
                     System.out.println("執行臨界區代碼");
                 } finally {
                     lock.unlock("my_lock");
                 }
             } else {
                 System.out.println("無法獲取鎖");
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 }
總結
以上三種方式是常見的Java分布式鎖實現方法。選擇哪種方法取決于你的具體需求和技術棧:
- Redis:簡單易用,適合輕量級應用。
- Zookeeper:功能強大,適合復雜分布式環境。
- 數據庫:適用于事務處理,但性能較低。