项目使用到集群环境,流程发送时如果确保一个流程不会被两个流程同时调用?
有一种办法是用文件锁的方式来实现。
代码如下:
锁接口:
package lock; import java.io.FileNotFoundException; import java.io.IOException; public interface Lock { /** * 检测是否被锁定 * @return true被锁定 ,false空闲 * */ public abstract boolean isLocked() throws FileNotFoundException; /** * 获取锁资源 * @return true成功锁定目标资源 ,false锁定操作失败 * */ public abstract boolean obtain() throws IOException; /** * 释放锁 * */ public abstract void unlock(); }
文件锁的实现:
package lock; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; public class FileProgrameLock implements Lock{ private String callerThreadID = null; private String lockFileName = null; FileChannel channel = null; private FileLock lock = null; public static Lock get(String fileName,String callerThreadID){ FileProgrameLock d = new FileProgrameLock(fileName); d.callerThreadID = callerThreadID; return (Lock)d; } public FileProgrameLock(String lockFileName){ this.lockFileName = lockFileName; } /** * 检测是否被锁定-不建议使用 * @return true被锁定 ,false空闲 * @deprecated * */ public boolean isLocked() throws FileNotFoundException { File tf = new File(lockFileName); if( ! tf.exists()){ return false; } FileChannel __channel = new RandomAccessFile(tf, "rw").getChannel(); FileLock tl = null; try { tl = __channel.tryLock(); if (tl == null) { return true; } else { return false; } } catch (OverlappingFileLockException e) { return true; } catch (IOException e) { return true; }catch (Exception e) { return true; }finally{ try { if(tl != null){ tl.release(); } tl = null; if(__channel.isOpen()){ __channel.close(); } __channel = null; tf = null; } catch (IOException e) { e.printStackTrace(); } } } /** * 获取锁资源 * @return true成功锁定目标资源 ,false锁定操作失败 * */ public boolean obtain() throws IOException { File tf = new File(lockFileName); createFile(); channel = new RandomAccessFile(tf, "rw").getChannel(); try { // System.out.println("get lock 000 >>>>>>>>>>>>>>>"); lock = channel.lock(); // System.out.println("get lock >>>>>>>>>>>>>>>"); return true; } catch (OverlappingFileLockException e) { return false; }catch (Exception e) { return false; } } /** * 释放锁 * */ public void unlock() { try { if(lock != null){ lock.release(); } System.out.println(callerThreadID + " unlock XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "); if(channel != null && channel.isOpen()){ channel.close(); } lock = null; channel = null; this.deleteFile(); } catch (IOException e) { } } protected void finalize() throws Throwable { System.out.println(callerThreadID + this.getClass() + " .finalize()"); super.finalize(); } private void createFile() throws IOException{ try{ File tf = new File(lockFileName); if(! tf.exists()){ tf.createNewFile(); } tf = null; }catch(IOException e){ System.out.println(e+lockFileName); throw e; } } private void deleteFile(){ File tf = new File(lockFileName); if(tf.exists()){ tf.delete(); } tf = null; } }
工厂类:
package lock; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class MakeLock implements Runnable{ private String threadID = ""; public void run() { try { while(true) { test2(threadID); Thread.sleep(200); } } catch (IOException e) { System.out.println(e); e.printStackTrace(); } catch (InterruptedException e) { System.out.println(e); } } public void test2(String threadID) throws FileNotFoundException, IOException, InterruptedException{ Lock lock = new MakeLock(threadID).getLock("c:/001/lockfile001.lock",threadID); System.out.println(threadID+":obtain..."); boolean b = lock.obtain(); //当有重叠时会发生等待,所以外侧先执行isLocked()判断 System.out.println(threadID+":obtained "+b); if(b){//执行业务逻辑 Thread.sleep(390); for(int i = 0 ; i < Integer.MAX_VALUE ; i ++){ ; } lock.unlock(); } lock = null; } public MakeLock(String threadID){ this.threadID = threadID; } public Lock getLock(String name,String threadID) { final StringBuffer buf = new StringBuffer(); return FileProgrameLock.get(name,threadID); } }
使用方法:
public void test2(String threadID) throws FileNotFoundException, IOException, InterruptedException{ Lock lock = new MakeLock(threadID).getLock("c:/001/lockfile001.lock",threadID); if (!lock.isLocked()) { System.out.println(threadID+":obtain..."); boolean b = lock.obtain(); System.out.println(threadID+":obtained "+b); if(b){//执行业务逻辑 Thread.sleep(390); for(int i = 0 ; i < Integer.MAX_VALUE ; i ++){ ; } lock.unlock(); } }else{ System.out.println(threadID+":can't get a lock :"+lock); } lock = null; }
多线程调用测试:
public static void main(String[] args) { //new AAA().test(); System.out.println("========================================="); Thread th1 = new Thread(new MakeLock("==================== thread1 ====================")); Thread th2 = new Thread(new MakeLock("#################### thread2 ####################")); Thread th3 = new Thread(new MakeLock("@@@@@@@@@@@@@@@@@@@@ thread3 @@@@@@@@@@@@@@@@@@@@")); Thread th4 = new Thread(new MakeLock("$$$$$$$$$$$$$$$$$$$$ thread4 $$$$$$$$$$$$$$$$$$$$")); Thread th5 = new Thread(new MakeLock("&&&&&&&&&&&&&&&&&&&& thread5 &&&&&&&&&&&&&&&&&&&&")); th1.start(); th2.start(); th3.start(); th4.start(); th5.start(); }
=================
经测试可以在共享文件系统下工作。
附件中AAA.java多线程测试代码可以直接运行。