顯示具有 java 標籤的文章。 顯示所有文章
顯示具有 java 標籤的文章。 顯示所有文章

2012年7月27日 星期五

Design Pattern: Singleton in JAVA, C#, C++

定義:
         保證一個class只有一個實體(Instance),並為它提供一個全域的訪問點(global access point)。

有的時候我們希望某個Class只會有一個Instance被產生。例如,Android中如果多個thread去access同一個DB就會產生錯誤。因此我們可能會希望透過一個Instance統一由他去Access 同一個DB。

在JAVA中實作的方式如下:
public class Singleton {
    private volatile Singleton instance = null;
        public Singleton getInstance() {
            if (instance == null) {
                synchronized(this) {
                    if (instance == null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }

深入探討:
為了避免multi-thread 的race condition發生及效率,這裡使用double check locking。避免race condtion的發生所以使用synchronized()。但是synchronized()可能造成performance的低落。因此在外層先判斷如果真的是null才進入critical section否則直接return。


在JDK 4(包含)以下的版本不支援volatile。volatile保證再每次取此變數的值時會去memory抓取而非從cache讀取。不加volatile有可能導致程式碼執行順序被 re-order。進而發生其他thread執行實可能看到非null的instance(但他這個時候明明是null)。

另外,上述的作法是lazy-Initialization的作法。也就是說當真正需要的時候才會被new出來。但是如果我們很確定程式中一定會去new這個物件,其實先把他new 出來也不會有什麼損失。


Singleton without Lazy-Initialization
public class Singleton {
    private volatile Singleton instance = new Singleton();
        public Singleton getInstance() {
            return instance;
        }
    }

這樣做的另外一個好處 程式碼看起來也比較清爽。
_____________________________________________________________________________________________________________


在C#方式如下:
using System;

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

在上面的code中,使用sealed來避免被繼承進而發生可能產生多個instance。另外使用lock的方法來避免multi-thread的race condition。如同在JAVA說的,volatile可以避免out of order所造成的問題。另外,如果不需要lazy-initialization我們可以這樣寫:
public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();
   
   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}


使用readonly來保證instance只會在static initialization過程時或是在class constructor裡被建立。
_____________________________________________________________________________________________________________


在C++的實作就比較簡單了:
class Singleton {
public: 
    static Singleton* Instance(){
    if (_instance == 0) {
        _instance = new Singleton;
    }
    return _instance;
}
protected: 
    Singleton();
private:
    static Singleton* _instance=0;
}

然而這個作法不是thread safe的。在C++使用如上面提到的Double checked locking方法及使用volatile並不能保證out of order的問題。也就是說在C++上面使用volatile並無法像C#/JAVA上面來保證使用volatile的variable 不會被re-order。因此像下面的DCL的code還是無法保證Thread-Safe。
class  Singleton {  
public :  
    static  Singleton* Instance() {  
        Lock lock;  
        if  (_instance == 0) {  
            _instance =  new  Singleton;  
        }  
        return  _instance;  
    }  
private :  
    static  Singleton *  volatile  _instance;  
    Singleton(){  
    }  
};  

最後看到Solstice使用pthread解決這問題,如下:

#include 
template<typename T>
class Singleton : boost::noncopyable
{
public:
    static T& instance()
    {
        pthread_once(&ponce_, &Singleton::init);
        return *value_;
    }
    static void init()
    {
        value_ = new T();
    }
private:
    static pthread_once_t ponce_;
    static T* value_;
};
template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template<typename T>
T* Singleton<T>::value_ = NULL;

Reference:
                 Gossip@caterpillar Design Pattern: Simple Factory 模式
                 The "Double-Checked Locking is Broken" Declaration
                 MSDN:Implementing Singleton in C#
                 多线程服务器的常用编程模型

2012年3月22日 星期四

Android Conditional Compilation( JAVA)

我們都知道JAVA其實是不支援條件式編譯的 例如在C/C++

#ifdef CONFIG_XXX_YYY
        ...
#ENDIF

$ gcc xxx.c -DCONFIG_XXX_YYY


所以我的方法是,在JAVA的地方產生一個JAVA檔,內容為

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class ConditionFlag {
    public static final Set  ConditionConfig;
    static {
        HashSet  config =new HashSet();
        config.put("CONFIG_XXX_YYY");
        ConditionConfig = Collections.unmodifiableSet(config);
    }
}

在其他的程式碼裡就可以:

if(ConditionFlag.ConditionConfig.Contains("CONFIG_XXX_YYY")){
     ...
}

這樣應該可以達到類似的目的了

2011年2月25日 星期五

ObjectOutputStream送出的物件指向舊的物件?

假設我在Server端有以下的Code

HashMap<String,String> map=new HashMap<String,String> ();
ObjectOutputStream oos=new ObjectOutputStream(clientsocket.getOutputStream);
while(true){
       map.put(Long.toString(System.currentTimeMillis()),Long.toString(System.currentTimeMillis()));
       oos.writeObject(map);
}

另外一端收到的會發現後面收到的物件都跟第一次收到的物件一樣,Why?因為在送出的時候都是指向同一個位址,因此必須要加上oos.reset();結果才會正確。

2011年2月7日 星期一

File Transfer via Network using C vs. JAVA

這次的測試分別比較了使用gcc /gcc -O2 編譯而成的與javac 1.6.0_23 的版本編譯而成的執行檔來做比較,測試的兩台機器是在Lan環境下。測試的設備與程式碼如下:
CPU Intel(R) Core(TM) i7 CPU         950  @ 3.07GHz
MEMERY 6G
NETWORK 1G
TEST FILE 466819755 byte (tar.bz2 file)

測試程式如下:
C (copy from http://content.edu.tw/primary/info_edu/cy_sa/report/more/8611a8.htm)
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#define TRUE 1
main()
{
int sock, msgsock, length;
struct sockaddr_in name;
FILE *fp;
int rval,wrval;
char buf[1024],filename[1024];

sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/*-------------------------------------------------------*/
/* Create the acceptable connection host with Wildcard */
/*-------------------------------------------------------*/
name.sin_family = AF_INET;
name.sin_addr.s_addr = INADDR_ANY;
name.sin_port = 5000;
if (bind(sock, (struct sockaddr *)&name, sizeof name) < 0) {
perror ("binding stream socket");
exit(1);
}
listen(sock,5);
do{
msgsock = accept(sock,(struct sockaddr *)0, (int *)0);
if (msgsock == -1)
perror("accept error !\\n ");
else do {
bzero(buf, sizeof(buf) );
/*--------------------------------------------------*/
/* Read filename from msgsock (sent from client) */
/*--------------------------------------------------*/
if ((rval = read(msgsock, buf,1024)) < 0)
perror("reading stream message");
if (rval == 0)
printf("Ending connection\\n");
else {
if ((fp=fopen(buf,"r")) == NULL) {
printf("file not found : %s !\\n ",buf);
break;
}
printf("opening [%s] !!\\n ",buf);
bzero(filename,sizeof(filename));
strcpy(filename, buf);
/*--------------------------------------------------*/
/* Read file content & sent to msgsock ...> client */
/*--------------------------------------------------*/
while (fgets(buf,sizeof(buf),fp) != (char*)NULL) {
if ((wrval=write(msgsock,buf,sizeof(buf))) <0)
break;
//printf(".");
}
fclose(fp);
printf("\\n\\n closing [%s] ! \\n",filename);
rval=0;
}
}while (rval != 0);
close(msgsock);
printf(" [%s]finish* !! \\n ",filename);
}while (TRUE);
close(sock);
exit(0);
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define DATA "The sea is clam ...."
main(int argc, char *argv[] )
{
int sock, rval, wrval;
char buf[1024];
struct sockaddr_in server;
struct hostent *hp, *gethostbyname();
FILE *fp;

sock = socket(AF_INET,SOCK_STREAM,0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sin_family=AF_INET;
hp=gethostbyname(argv[1]);
if (hp == 0 ) {
printf( "%s : unknown host\\n", argv[1]);
exit(2);
}
bcopy((char*)hp->h_addr, (char *)&server.sin_addr, hp->h_length);
server.sin_port = 5000;
if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0)
{
perror ("connecting stream socket");
exit(1);
}

if (write(sock, argv[3],strlen(argv[3])) < 0)
perror ("writing stream socket");
sleep(1);
printf("requiring [%s], ...\\n",argv[3]);
fp=fopen(argv[4],"w+");
/*---------------------------------------------------------*/
/* Read file content from sock (sent from ftp_serv ) */
/* and Write to local file */
/*---------------------------------------------------------*/
while ( (rval=read(sock,buf,sizeof(buf) )) >1) {
//printf(".");
fputs(buf,fp);
}
fclose(fp);
close(sock);
printf("finish !! \\n");
printf("closing connection !! \\n");
exit(0);
}

JAVA
server.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class server {
  public static void main(String[] args) throws IOException {
    ServerSocket servsock = new ServerSocket(5000);
    File myFile = new File("hadoop.tar.bz2");
    while (true) {
      Socket sock = servsock.accept();
      byte[] mybytearray = new byte[(int) myFile.length()];
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
      bis.read(mybytearray, 0, mybytearray.length);
      OutputStream os = sock.getOutputStream();
      os.write(mybytearray, 0, mybytearray.length);
      os.flush();
      sock.close();
    }
  }
}


client.java
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.Socket;

public class client {
  public static void main(String[] argv) throws Exception {
    Socket sock = new Socket("192.168.254.1", 5000);
    byte[] mybytearray = new byte[1024];
    InputStream is = sock.getInputStream();
    FileOutputStream fos = new FileOutputStream("hadoop.tar.bz2");
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    int bytesRead ;
   while((bytesRead= is.read(mybytearray, 0, mybytearray.length))!=-1){
    bos.write(mybytearray, 0, bytesRead);
    }
    bos.close();
    sock.close();
  }
}

測試結果如下:
Test Case Time(s)
C with -O2 20.539(s)
C without -O2 20.286(s)
JAVA 4.923(s)
很詭異的結果,再研究看看。

2011年1月28日 星期五

Java的List, Set, Map比較

首先我主要比較了
List: ArrayList, LinkedList
Set: HashSet, TreeSet
Map: HashMap, TreeMap
並且針對了這幾個新增刪除以及取得(Get)來做比較,測試方式是先新增10000個字串物件,然後刪除字串為"5000”的物件,再來則是利用while loop及foreach來展開全部的物件。
實驗環境為
CPU Intel core i7 860 @2.80GHz
OS WIndows 7 X86_64
MEM 6G
JDK Java SE 6 Update 23

以下為數據結果:
add(push) delete(remove) Get(foreach) Get (while)
ArrayList 10 1 2 4
LinkedList 4 1 1 4
HashSet 13 0 2 5
TreeSet 38 0 4 6
HashMap 3 0 N/A 4
TreeMap 7 0 N/A 4
image

程式碼如下

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.TreeMap;
import java.util.TreeSet;


public class PerformanceTest {
 
 private static void ArrayListTest(int size){
  System.out.println("\nArrayListTest, Total size: "+size);
  ArrayList<String> list=new ArrayList<String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.add(Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
  System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Iterator iterator = list.iterator();
  String s;
        while(iterator.hasNext()) {
         s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  for(String i : list) {
   s=i;
        }
  System.out.println("4.Get time(use enhanced for loop): "+(System.currentTimeMillis()-start)+" (ms)");
 }
 
 private static void LinkedListTest(int size){
  System.out.println("\nLinkedListTest, Total size: "+size);
  LinkedList<String> list=new LinkedList<String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.add(Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
  System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Iterator iterator = list.iterator();
  String s;
        while(iterator.hasNext()) {
         s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  for(String i : list) {
   s=i;
        }
  System.out.println("4.Get time(use enhanced for loop): "+(System.currentTimeMillis()-start)+" (ms)");
 }
 
 private static void HashSetTest(int size){
  System.out.println("\nHashSetTest, Total size: "+size);
  HashSet<String> list=new HashSet<String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.add(Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
   System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Iterator iterator = list.iterator();
  String s;
        while(iterator.hasNext()) {
         s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  for(String i : list) {
   s=i;
        }
  System.out.println("4.Get time(use enhanced for loop): "+(System.currentTimeMillis()-start)+" (ms)");
 }
 
 private static void TreeSetTest(int size){
  System.out.println("\nTreeSetTest, Total size: "+size);
  TreeSet<String> list=new TreeSet<String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.add(Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
   System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Iterator iterator = list.iterator();
  String s;
        while(iterator.hasNext()) {
         s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  for(String i : list) {
   s=i;
        }
  System.out.println("4.Get time(use enhanced for loop): "+(System.currentTimeMillis()-start)+" (ms)");
 }
 
 private static void HashMapTest(int size){
  System.out.println("\nHashMapTest, Total size: "+size);
  HashMap<String,String> list=new HashMap<String,String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.put(Integer.toString(i),Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
   System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Collection collection = list.values();
        Iterator iterator = collection.iterator();
        String s;
        while(iterator.hasNext()) {
            s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  
 }
 
 private static void TreeMapTest(int size){
  System.out.println("\nTreeMapTest, Total size: "+size);
  TreeMap<String,String> list=new TreeMap<String,String>();
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++){
   list.put(Integer.toString(i),Integer.toString(i));
  }
  System.out.println("1.Add time: "+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  
   list.remove(Integer.toString(size/2));
  
   System.out.println("2.Delete time(delete the object "+size/2+") :"+(System.currentTimeMillis()-start)+" (ms)");
  
  start=System.currentTimeMillis();
  Collection collection = list.values();
        Iterator iterator = collection.iterator();
        String s;
        while(iterator.hasNext()) {
            s=(String) iterator.next();
        }
  System.out.println("3.Get time(use iterator): "+(System.currentTimeMillis()-start)+" (ms)");
  
  
 }
 public static void main(String[] args) {
  ArrayListTest(10000);
  LinkedListTest(10000);
  HashSetTest(10000);
  TreeSetTest(10000);
  HashMapTest(10000);
  TreeMapTest(10000);
 }
}