歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

單機上多JVM同步控制的一種方法

在一個JVM進程中的同步控制,無非就是線程之間的同步問題,但要想在多JVM進程之間實現訪問本地系統資源的同步,卻並非JVM所擅長的了。當然,若依賴第三方Master主控進程,這個問題還是可以解決的。多於簡單的系統而言,這樣做無疑會增加系統的復雜性,從而導致整個系統的不穩定性和潛在的不安全。所以,下面就如何在單機上實現多JVM進程之間的同步控制,給出了一個簡單的方法。

JDK 1.4的文件鎖"file locking"允許你以文件為共享資源,對訪問進行同步化處理(allows you to synchronize access to a file as a shared resource)。但是,競爭文件的兩個線程必須屬於兩個不同的JVM,或者一個是Java線程,另一個是操作系統的本地線程。由於Java的文件鎖是直接映射操作系統的鎖機制的,因此其它進程也能看到文件鎖。 

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class TestRandomAccessFile {
   
   
    public static void testTryLock(){
        RandomAccessFile f1=null;
        RandomAccessFile f2=null;
       
        FileChannel channel1=null;
        FileChannel channel2=null;
       
        FileLock lock1=null;
        FileLock lock2=null;
       
        try {
            f1=new RandomAccessFile("test.txt","rw");
            //f1.writeChars("asd");
            channel1 = f1.getChannel();
           
            lock1 = channel1.tryLock();
            if(lock1!=null) System.out.println("1:success");
            else System.out.println("1:fail");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        try {
            f2=new RandomAccessFile("test.txt","rw");
            //f2.writeChars("123");
            channel2 = f1.getChannel();
           
            lock2 = channel2.tryLock();
           
            if(lock2!=null) System.out.println("1:success");
            else System.out.println("1:fail");
           
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
       
        try {
            if(lock1!=null) lock1.release();
            if(lock2!=null) lock1.release();
           
            if(channel1!=null) channel1.close();
            if(channel2!=null) channel2.close();
           
           
            if(f1!=null) f1.close();
            if(f2!=null) f2.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
       
    }

    public static void testLock(){
        RandomAccessFile f1=null;
        RandomAccessFile f2=null;
       
        FileChannel channel1=null;
        FileChannel channel2=null;
       
        FileLock lock1=null;
        FileLock lock2=null;
       
        try {
            f1=new RandomAccessFile("test.txt","rw");
            //f1.writeChars("asd");
            channel1 = f1.getChannel();
           
            lock1 = channel1.lock();
            if(lock1!=null) System.out.println("1:success");
            else System.out.println("1:fail");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        try {
            f2=new RandomAccessFile("test.txt","rw");
            //f2.writeChars("123");
            channel2 = f1.getChannel();
           
            lock2 = channel2.lock();
           
            if(lock2!=null) System.out.println("1:success");
            else System.out.println("1:fail");
           
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
       
        try {
            if(lock1!=null) lock1.release();
            if(lock2!=null) lock1.release();
           
            if(channel1!=null) channel1.close();
            if(channel2!=null) channel2.close();
           
           
            if(f1!=null) f1.close();
            if(f2!=null) f2.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
       
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
       
        testTryLock();
       // testLock();
       
    }

}

��接運行會出現:

1:success
Exception in thread "main" java.nio.channels.OverlappingFileLockException
    at sun.nio.ch.FileChannelImpl$SharedFileLockTable.checkList(Unknown Source)
    at sun.nio.ch.FileChannelImpl$SharedFileLockTable.add(Unknown Source)
    at sun.nio.ch.FileChannelImpl.lock(Unknown Source)
    at java.nio.channels.FileChannel.lock(Unknown Source)
    at test.TestRandomAccessFile.testLock(TestRandomAccessFile.java:107)
    at test.TestRandomAccessFile.main(TestRandomAccessFile.java:147)

一個JVM運行一半,另一個運行全部,

運行一半的 JVM 會出現:

1:success

運行全部的 JVM 會出現:

1:fail
1:fail

要想獲取整個文件的鎖,可以用FileChannel的tryLock( )或lock( )方法。(SocketChannel,DatagramChannel,以及 ServerSocketChannel是不需要鎖的,因為它們原本就是"進程實體(single-pricess entities)";一般來說,你是不會讓兩個進程去共享一個網絡socket的。)tryLock( ) 是非阻塞的。它會試著去獲取這個鎖,但是如果得不到(其它進程已經以獨占方式得到這個鎖了),那它就直接返回。而lock( )是阻塞的。如果得不到鎖,它會在一直處於阻塞狀態,除非它得到了鎖,或者你打斷了調用它(即lock( )方法)的線程,或者關閉了它要lock( )的channel,否則它是不會返回的。最後用FileLock.release( )釋放鎖。

關於 testLock();的測試這裡就不在給出具體的情況了。

Copyright © Linux教程網 All Rights Reserved