解決erlang和java同時操作一張表,造成鎖表問題,erlangjava
作者:張昌昌
1、問題描述
Erlang端通過odbc去寫oracle一張表,同時java通過jdbc驅動也去寫這張表,當同時多次發生這種寫操作時,這個表就被鎖。
2、問題解決
思路:利用適配器原理,適配erlang和java的資料庫連接,讓erlang端對資料表的操作與java端對該資料表的操作,分時序順序進行,其中一端在進行寫操作時上鎖
另一端就不能操作,直到他操作完成釋放鎖,另一端才能操作。
該適配器採用java編寫,通過otp.jar讓erlang與java進行通訊,erlang和java對資料表操作的串連都要從該適配器入
實現方式:
(1)java端
public class ConnectionAdaptor {
private static final ConnectionAdaptor instance = new ConnectionAdaptor("javaNode","theMailbox","secret");
private OtpNode node;
private static OtpMbox mbox;
private ReentrantLock lock = new ReentrantLock();
public static ConnectionAdaptor getInstance(){
return instance;
}
private ConnectionAdaptor(String nodeName,String mboxName,String cookie){
super();
try{
node=new OtpNode(nodeName,cookie);
}catch(IOException e){
e.printStackTrace();
}
System.out.print(node);
mbox = node.createMbox(mboxName);
}
private void process(){
while(true){
try{
OtpErlangObject msg = mbox.receive();
OtpErlangTuple t = (OtpErlangTuple)msg;
OtpErlangPid from = (OtpErlangPid)t.elementAt(0);
String name = ((OtpErlangString)t.elementAt(1)).stringValue();
if(name.equals("write_start"))
adaptor(1);
}catch(Exception e){
}
}
}
public static void main(String[] args){
//啟動一個線程用於erlang訊息的偵聽
new Thread(){
public void run(){
ConnectionAdaptor.getInstance().process();
}
}.start();
//啟動一個線程進行java端的資料表操作
new Thread(){
public void run()
{
for(int i=0;i<10;i++)
{
try{
try{
ConnectionAdaptor.getInstance().adaptor(2);
}catch(Exception e){
e.printStackTrace();
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}.start();
}
public void adaptor(int type){
lock.lock();
if (type == 1)
{
while(true)
{
OtpErlangObject msg = mbox.receive();
OtpErlangTuple t = (OtpErlangTuple)msg;
OtpErlangPid from = ((OtpErlangString)t.elementAt(1)).stringValue();
if(name.equals("write_end"))
{
System.out.println("erlang write table end");
lock.unlock();
}
}
}
else
{
Thread.sleep(5000);
System.out.println("java write table end");
lock.unlock();
}
}
}
erlang端:
-module(erl_to_java).
-export([write_table/0,start/1]).
write_table() ->
{theMailbox,javaNode@zcc}!{self(),"write_start"},
timer:sleep(5000),
{theMailbox,javaNode@zcc}!{self(),"write_end"}.
start(N) ->
case N =:= 0 of
true -> ok;
false -> write_table(),start(N-1)
end.
3、時序圖
4、問題總結
(1)java單例模式
(2)java與erlang通訊
(3)java線程間鎖機制
首先利用單例模式擷取一個配接器物件,然後啟動一個線程執行process(),偵聽來自erlang端的寫表訊息,一旦有erlang發出寫表請求,需加鎖,在erlang進程中執行
寫表操作後,向java進程發送寫表結束請求,然後java進程釋放鎖,一旦有java端寫表操作,便擷取鎖進行寫表操作,之後釋放鎖,在java寫表期間,erlang的寫表操作必須等待,直到鎖釋放,反之亦然。
5、使用方法
(1)運行該適配器的java端需要安裝erl的運行環境,需要匯入OtpErlang.jar包;
(2)erlang端節點啟動時,要和適配器單例建立時的cookie保持一致,同時
erl -sname erlangNode -setcookie secret -pa "erl_to_java.bin所在的路徑" -eval "net_adm:ping(javaNode@zcc)"