java split 공백

javascript 2012. 1. 3. 17:17 Posted by jiddong

스플릿 사용시 공백데이터를 주의해야한다. 

공백데이터를 스플릿으로 나눌시 데이터 갯수가 맞지 않음

제일 마지막에 오는 요소의 값이 없을 경우 그 요소를 무시하도록 되어 있음



StringTokenize


구분자 사이에 분해할 요소의 값이 존재하지 않으면 무시
완전하게 모든 요소의 값이 존재하는 경우라면 사용을 해도 되겠지만
가변적인 데이터라면 사용하기 꺼림직함

 

String.split(string text, int limite)

limit를 저정 하지 않았을 경우에는
제일 마지막에 오는 요소의 값이 없을 경우 그 요소를 무시하도록 되어 있음
  
limit를 지정 했을 경우 해당 숫자만큼만 분해.

limit는 분해를 한 후 얻고자 하는 String[]의 크기라고 보시면 됩니다.

limit가 분해하고자 하는 요소의 개수와 같거나 클 경우 배열의 개수만큼의 String[]을 되돌려 주지만, 요소의 개수보다 작을 경우 지정한 숫자만큼의 String[]으로 되돌려 줌

아래관련
소스들을 보시면 이해가능


관련 소스





  1.         public static void main(String[] args) {
  2.                 String recode = "a-b-c-d-e-f";
  3.                 String[] values = recode.split("-");
  4.                    System.out.print("length ::"+values.length + "\n");
  5.                                  
  6.                   for(int i=0 ; i<values.length ; i++) {
  7.                    System.out.print("values["+i+"]::["+values[i]+"]\n");
  8.                   }
  9.  
  10.         }
  11.        
  12.         //출력값
    스플릿된 갯수 만큼 length 가 나오고 있음
  13. length ::6
    values[0]::[a]
    values[1]::[b]
    values[2]::[c]
    values[3]::[d]
    values[4]::[e]
    values[5]::[f]

  14.  
  15. }

  1.         public static void main(String[] args) {
  2.                 String recode = "a-b-c-d-e-f--------"; 데이터가 없다면!!!!????
  3.                 String[] values = recode.split("-"); 리미트값 없음
  4.                    System.out.print("length ::"+values.length + "\n");
  5.                                  
  6.                   for(int i=0 ; i<values.length ; i++) {
  7.                    System.out.print("values["+i+"]::["+values[i]+"]\n");
  8.                   }
  9.  
  10.         }
  11.         
    split()함수에 Limite 값이 없기 때문에 값이 없는 데이터는 무시됨
    스플릿된 갯수 만큼 length 가 나오고 있음

    length ::6

  12. values[0]::[a]
    values[1]::[b]
    values[2]::[c]
    values[3]::[d]
    values[4]::[e]
    values[5]::[f]

  13.  
  14. }
 
  1.         public static void main(String[] args) {
  2.                 String recode = "a-b-c-d-e-f--------";
  3.                 String[] values = recode.split("-", 20); 리미트 값이 생겨땅!!!
  4.                    System.out.print("length ::"+values.length + "\n");
  5.                                  
  6.                   for(int i=0 ; i<values.length ; i++) {
  7.                    System.out.print("values["+i+"]::["+values[i]+"]\n");
  8.                   }
  9.  
  10.         }
  11.         
    split()함수에 limite 값이  있 기  때문에 값이 없는 데이터와 토큰뒤도 또한 스플릿데된 데이터로 나옴
    스플릿된 갯수 만큼 length 가 나오고 있음

    length ::14

  12. length ::14
    values[0]::[a]
    values[1]::[b]
    values[2]::[c]
    values[3]::[d]
    values[4]::[e]
    values[5]::[f]
    values[6]::[] //공백도 데이터로 본다 리미트가 있다면
    values[7]::[]
    values[8]::[]
    values[9]::[]
    values[10]::[]
    values[11]::[]
    values[12]::[]
    values[13]::[]


  13.  
  14. }
  

  1.         public static void main(String[] args) {
  2.                 String recode = "a-b-c-d-e-f- - - - - - - -"; 공백을 넣었당
  3.                 String[] values = recode.split("-");
  4.                    System.out.print("length ::"+values.length + "\n");
  5.                                  
  6.                   for(int i=0 ; i<values.length ; i++) {
  7.                    System.out.print("values["+i+"]::["+values[i]+"]\n");
  8.                   }
  9.  
  10.         }
  11.        

    split()함수에 Limite 값이 없기 때문에 마지막 토큰뒤에 값이 없는 데이터는 무시됨
  12. 스플릿된 갯수 만큼 length 가 나오고 있음

    length ::13 
    13 이 나오는 이유는 마지막 토큰 뒤에 데이터가 없기 때문에 스플릿이 제외됨
  13. values[0]::[a]
    values[1]::[b]
    values[2]::[c]
    values[3]::[d]
    values[4]::[e]
    values[5]::[f]
    values[6]::[ ]
    values[7]::[ ]
    values[8]::[ ]
    values[9]::[ ]
    values[10]::[ ]
    values[11]::[ ]
    values[12]::[ ]

  14.  
  15.  
  16. }


  1.         /**
  2.          * @param args
  3.          */
  4.         public static void main(String[] args) {
  5.                 String recode = "a-b-c-d-e-f- - - - - - - -";
  6.                 String[] values = recode.split("-"20);
  7.                    System.out.print("length ::"+values.length + "\n");
  8.                                  
  9.                   for(int i=0 ; i<values.length ; i++) {
  10.                    System.out.print("values["+i+"]::["+values[i]+"]\n");
  11.                   }
  12.  
  13.         }
  14.       
    split()함수에 Limite 값이 있기 때문에 마지막토큰 뒤에도 데이터가 있는것으로 간주함
  15. length : 14

  16.   
  17. length ::14
    values[0]::[a]
    values[1]::[b]
    values[2]::[c]
    values[3]::[d]
    values[4]::[e]
    values[5]::[f]
    values[6]::[ ]
    values[7]::[ ]
    values[8]::[ ]
    values[9]::[ ]
    values[10]::[ ]
    values[11]::[ ]
    values[12]::[ ]
    values[13]::[]

  18.  
  19.  
  20. }










 

Android Proguard 설정법 libs 라이브러리 포함

android 2011. 12. 27. 20:31 Posted by jiddong
프로가드가 많이 바뀌었다..
요즘적용을 안하다보니... 최신기준으로 수정 작성함

기본 프로젝트 생성을 하면

proguard-project.txt  = 프로가드 세팅 파일
project.properties = 프로젝트 세팅파일

project.properties 프로젝트 세팅파일에  프로가드 사용 여부 주석을 해제 하자
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
해제방법은 # 을 삭제

안드로이드 signkey 로 바이너리를 만들면  

자동으로  Proguard 설정되어짐 확인방법은

android proguard 폴더 아래 4개의 File 생성되야 적용된것임

  • dump.txt :  어플리케이션에서 사용중인 클래스들의 내부 구조에 대한 대략적인 정보를 
  • mapping.txt :  난독화 과정에서 기존 클래스 혹은 메서드가 어떤 새로운 난독화된 이름으로 매핑되었는지 그 목록. 난독화 된 어플리케이션에 발생하는 로그나, 스택 트레이스 들을 분석하기 위해서 꼭 챙겨 두셔야 합니다.
  • seeds.txt : 난독화 되지 않은 클래스와 멤버들의 목록입니다.
  • usage.txt : 사용되지 않기 때문에, apk 파일에서 제거된 코드들의 목록입니다. 혹시 제거되서는 안되는 메서드나 클래스가 제거되었는지 꼭 확인

  


문제가 생길시 파일 설정방법(라이브러리 추가나 메소드가 변경되어 메소드등이 없다고 나올때)

project.properties  File

#프로가드 사용여부

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

#프로젝트  지정 sdk 본인의 프로젝트에 알맞은 sdk 사용

target=android-17 


proguard-project.txt  File


-verbose //로그 봄
-dontoptimize // 압축 하지 않음 그냥 하지말자... 
-dontshrink  //사용하지 않는 메소드를 유지하라

-dontwarn org.apache.**  
-dontwarn (Warnig이 나온 클래스).** 
// 빌드시 can't find superclass or interface // can't find referenced class 등의  Warnig 이 나올경우
//클래스 Warnig 을 무시 한다 

-libraryjars libs/android-support-v4.jar // 라이브러리 추가
-libraryjars libs/json-simple-1.1.1 .jar

-keep public class * { public protected *; } 
//public class 와   protected class 의 경우 를 난독화 하지 않는다. 
//public class 를 난독화 할경우 메소드 호출중 문제가 될수 있음....

-keep class org.apache.http.** //org.apache.http.하위 클래스를 전부 난독화 하지 않음 
-keep interface org.apache.http.** //org.apache.http.  하위 인터페이스를 난독화 하지 않는다

-keep class  org.apache.http.** {

public *;

// org.apache.http.하위 클래스중 public method 만 난독화 하지 않음

난독화후 어플리케이션 실행하여 돌려보면서 난독화 범위를 적용해야함.













Android Java Script를 이용하여 Android APP을 만들때 script file과 html file을 asset 에 저장을 해서

java script 를 사용할경우 

바이너리 배포시에 APK 파일안의 assets 폴더를 볼수있기때문에 보안적 이슈가 생깁니다.

예를 들어 key 값이나 로직등등~

예방할 방법은 하드코딩으로으로 Html 이나 Java script file를 String 으로 java class 안에 가지고 있고
스크립트 사용시   Html 이나 Java script file 을 local 에 생성하여 사용하면 됩니다.

Progard 를 적용한다 하여도 String 객체는 안적용된다는 말이있는데 확인을 해봐야할듯;; 

디컴 파일 해서 그렇게 까지 보고싶으면 어쩔수 없뜸 ㅋㅋ


그런데! 제가 하루동안 헤매인 이유는 local에 저장을 했을 경우 그 위치가 어디인가 입니다.

그 위치는

file:///data/data/패키지 이름/files/파일명입니다~

그리구 만약 스크립트 안의  src='script.js'  요런 부분 도
  src='file:///data/data/패키지/files/script.js'  요리 바꿔줘야겠죠~ ㅋ

아래는  String 을 local file 로 저장하는 함수

 

  1. /**
  2.          * java script html file  을 <br>
  3.          *file:///data/data/패키지명/files/ 위치에 생성해준다.<br>
  4.          *
  5.          * @param oContext
  6.          * @return String HTML 파일 위치 값
  7.          */
  8.         private String copyHTML(Context oContext){
  9.                  String sResult = null;
  10.                  try {
  11.  //기존 HTML file 삭제 file 양이 크지 않아 삭제후 재 복사하여도 속도에 이슈가 없어서
  12.  //훗날 업데이트시 스팸메일 변경을 대비하여 삭제하고 재 생성
    // 파일의 크기가 클경우 생성후 있으면 재생성하지 않는 로직 필요
  13.                          deleteHTML(oContext);
  14.                          
  15.                         oContext.getFilesDir();
  16.                 File oDir = oContext.getFilesDir();
  17.                 oDir.mkdir();
  18.                 File oFile = new File(oDir.getAbsolutePath()+"/" + FILE_NAME);
  19.                 String sPath = oFile.getAbsolutePath();
  20.                
  21.                 //파일이 있을경우
  22.                 if(oFile.exists()){
  23.                         sResult =  "file://" + sPath;
  24.                         return sResult;
  25.                 }
  26.                                                
  27.                 FileOutputStream fo = new FileOutputStream(oFile);                    
  28.                 OutputStreamWriter osw = new OutputStreamWriter(fo);
  29.                 BufferedWriter bw = new BufferedWriter(osw);
  30.                
  31.                 bw.write(SPAM_HTML); // local 에 저장할 문서 
  32.                 bw.flush();
  33.                
  34.                 bw.close();
  35.                 osw.close();
  36.                 fo.close();
  37.  
  38.                 sResult =  "file://" + sPath;
  39.                
  40.         } catch (FileNotFoundException e) {
  41.                 sResult = null;
  42.                 deleteHTML(oContext);
  43.                         e.printStackTrace();
  44.          } catch (IOException e) {
  45.                  sResult = null;
  46.                  deleteHTML(oContext);
  47.                   e.printStackTrace();
  48.          }
  49.                
  50.                 return sResult;
  51.          }
  52.  
  53.  
  54.         /**
  55.          * 파일 유무확인해 HTML 파일이 있을경우 삭제
  56.          * @param oContext
  57.          */
  58.         private void deleteHTML(Context oContext) {
  59.                 oContext.getFilesDir();
  60.                 File oDir = oContext.getFilesDir();
  61.                 oDir.mkdir();
  62.                 File oFile = new File(oDir.getAbsolutePath() + "/" + FILE_NAME);
  63.  
  64.                 // 파일이 있을경우
  65.                 if (oFile.exists()) {
  66.                         oFile.delete();
  67.                 }
  68.         }

만약 Android Javascript WebView client 를 모른다! 

http://developer.android.com/guide/webapps/webview.html 

디벨로퍼에 가시면 자세히 나와있습니다~~




Android TextView 안에 이미지 추가

android 2011. 10. 13. 11:25 Posted by jiddong
  1.     /**
  2.      *  텍스트 앞에 이미지가 추가 된다
  3.      *
  4.      * @param tv
  5.      * @param text
  6.      */
  7.     private void setTitle(TextView tv, String text, boolean isAdult) {
  8.         if(!isAdult) {
  9.             tv.setText(text);
  10.         } else {
  11.             tv.setText(Html.fromHtml("<img src=\"이미지름\"/>" + text, new ImageGetter()null));
  12.  
  13.         }
  14.     }
  15.  
  16.     private final String PACKAGE_NAME = "패키지명";
  17.  
  18.     public class ImageGetter implements Html.ImageGetter {
  19.  
  20.         @Override
  21.         public Drawable getDrawable(String source) {
  22.             int nID = 0;
  23.             nID = getResources().getIdentifier(source, "drawable", PACKAGE_NAME);
  24.             Drawable d = getResources().getDrawable(nID);
  25.             d.setBounds(00, d.getIntrinsicWidth() + 6, d.getIntrinsicHeight());
  26.             return d;
  27.         }
  28.     }

Java 기본 변수

java 2011. 8. 25. 15:05 Posted by jiddong


1 Bit
 - 0 과 1 로된 단위

1Byte
 - 8 bit 로 구성
0000 0000 이것은 16진수로 0X00 으로 표현  

Java 기본형(Primitive type)

우선 Java 는 데이터를 다루는
최소의 단위가 1Byte임을 알자 




  1 Byte (8 Bit)   2 Byte (16 Bit) 4 Byte (32 Bit)  8 Byte (64 Bit) 
 논리형  boolean       
 문자형   char (unsinged)     
 정수형 byte  short  int  long 
 실수형     float  double 


boolean 
 - 저장 가능한 범위  true/ false 
 - Java 가 데이터를 다루는 최소 범위가 1 Byte 이기 때문에 낭비적이긴 하지만 1 Byte 사용

char 
 - Java의경우 Unicode 를 사용 동양의 글자의 경우 2 Byte 필요하기때문에 char 의경우 2 Byte 이용

 - Java 에서 유일하게 제공되는 
unsinged 형태 (음수 가존재 하지 않음 )
   *  2 Byte  =  16진수 0x00 =  
0000 0000  0000 0000
      맨앞 1 Bit를 가지고 음수나 양수 를 나타냄 하지만 char 형은 
unsinged 형식이기 때문에
      맨 앞 비트를 음수 양수 형식 으로 사용하지 않음
   

      char 형이   1111 1111   1111 1111 의 Bit를 가지고 있을때 10진수의 값 65535
      short 형이  
1111 1111  1111 1111 의 Bit를 가지고 있을때  10진수의 값 -1 

 - char a = 'A'; b = 'B'; 일때 if (a > b) 가 가능한이유 
   *  char 형은 유니코드 정수형태로 저장 char a = 'A' 일시 a변수에는 'A' 의 정수 값인 65가 들어감

byte , short , int , long

- 각형의 표현범위 
  
 byte  -128 ~ 127
(-2의 7승 ~ 2의 7승 -1 )
 shot  -32,768 ~ 32,767
(-2의 15승 ~ -2의 15승 -1)
 int  -2147483648 ~ 2147483647
(-2의 31승 ~ 2의 31승 -1)
 long  무지큼;;;
(-2의 63승 ~ 2의 63승 -1)


 - byte, short 가 더적은  Bit를 가지고 있어 메모리를 조금더 절약할수 있지만  int를 사용하자
   *  JVM 의 피연산자 스택이 피연산자를 4 Byte 단위로 저장 하기 때문에
       int 보다 작은 자료형의 값을 계산시 int 형으로 형변환 되서 연산이 수행됨

 - 요기서 질문 int 1 과 -1을 bit 형태로 표현하면?
   * int 1 = 4 byte = 32 bit 
             
0000 0000, 0000 0000, 0000 0000, 0000 0001
     int -1 = 4 byte = 32 bit 
             
1111 1111, 1111 1111, 1111 1111, 1111 1111
     int -2 = 4 byte = 32 bit 
             
1111 1111, 1111 1111, 1111 1111, 1111 1110
     int -3 = 4 byte = 32 bit 
              
1111 1111, 1111 1111, 1111 1111, 1111 1101 
    맨처음 singed Bit 를 보고 1일경우 음수이기 때문에
    앞의 첫번째 Bit 부터 0이 나올때까지 모든 Bit 를 1로 변경해주면 음수가 됨    

Test Code    
 
    
int shTemp = 0;
   
    shTemp =  ~shTemp; // 1의 보수 표현(not)  각 비트를 반전시킨 값을 반환한다.

    System.out.println("short ::"+shTemp);


  출력 값  short ::-1

float, double
   
 - float 보다 double 이 약 두배의 정밀도를 가지고 있음
 
- 정수형에서 기본 자료형이 int 형이듯 실수형에서는 double 형이 기본자료형이기 때문에
    float pi = 3.14F  뒤에 붙은 리터럴형을 사용하지 않으면 double 형으로 사용된다
   * float pi = 3.14; 이면 오류 발생 float 형 변수에 double 형을 저장할수 없음. 

- double Temp = 1e-3; 이란 ?
   * e 뒤에 붙은 숫자가 10의 몇승을 나타냄
     지금 1e-3의 경우 10의 -3승 으로서 0.001 과 같음 
     1e3 == 1000 (10의 3승 )과 같음 
   



















'java' 카테고리의 다른 글

정규 표현식 기본  (0) 2012.11.23
Java Thread Pool 좋은 글(Object Pool Control)  (0) 2010.12.17

한글계정 Android avd 실행시 문제 해결

android 2011. 6. 21. 13:05 Posted by jiddong
C:\android-sdk-windows\platform-tools 환경 변수 추가
 
avd 가 동작하지 않는 폴더

C:\Documents and Settings\ XXX \.android\avd 에 가서
 
android move avd -n galtab -p c:/avd 라고 입력한다
 

android app label, name, package name 알아보기~

android 2011. 4. 27. 17:17 Posted by jiddong
함수 하나로 끝~

AppLabel 이 아이콘 아래나오는 앺이름~

public void getAppList(){
 
PackageManager packagemanager = this.getPackageManager();
List< ApplicationInfo > appList = packagemanager.getInstalledApplications( 0 );
Log.d(TAG, ""+ appList.size());
for (int i = 0; i < appList.size(); i++) {
Log.d(TAG, "=========================================================");

Log.d(TAG, "++ packageName  :: "+ appList.get(i).packageName);
Log.d(TAG, "++ processName  :: "+ appList.get(i).processName);
Log.d(TAG, "++ AppLabel  :: "+ appList.get(i).loadLabel(packagemanager));
Log.d(TAG, "++ AppIcon  :: "+ appList.get(i).loadIcon(packagemanager));
Log.d(TAG, "=========================================================");
Log.d(TAG, " ");
Log.d(TAG, " ");
}

Java Thread Pool 좋은 글(Object Pool Control)

java 2010. 12. 17. 18:24 Posted by jiddong

내용 참좋다 
멀티 Thread 시 참고 하기 좋음~

제목 : Object Pool Control 기법
글쓴이: 이원영(javaservice) 2000/11/21 04:59:10 조회수:25611 줄수:483
Object Pool Control 기법은 JDBC Connection Pool 을 만들거나, TCP/IP Socket Pool을 
만드는 등, 최근엔 많은 자바 개발자들이 즐겨 사용하는 기법 중의 하나 입니다.
특히 JDBC Connection Pool 이 소개 되면서, 너도 나도 직접 Connection Pool을
만드는 시도를 자연스럽게 하게 됩니다.

저 역시 그 중의 하나였고, Object Pooling 기법에 대해 너무 단순하고 쉽게 생각
했었습니다. 최근에야 저의 프로그래밍 기법에 엄청난 잘못이 있었다는 것을
하나은행과 한빛은행 인터넷뱅킹 프로젝트 튜닝작업을 하면서 깨달았습니다. 
저와 같은 잘못을, 행여나 다른 분들이 똑같이 범하지 않았으면 하는 바램에서 저의
잘못을 아래 처럼 기술합니다.


아래의 3 개의 클래스는 Object Pool 을 테스트 하는 프로그램입니다. 뭐가 잘못
되었을까요? 퀴즈입니다.


----8><--------------------------------------------------------------------
package badpool;
/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class BadPoolTest extends Thread{
    private int client = 0;
    public BadPoolTest(int n){
        this.client = n;
    }
    public static void main(java.lang.String[] args) {
        // PoolObject 의 최대값인 20 보다 많은 요청을 보내어야 테스트가 됨.
        int max = 40;
        System.out.println("Calling " + max + " threads");

        Thread[] threads = new BadPoolTest[max];
        for(int i=0;i<max;i++){
            threads[i] = new BadPoolTest(i);
            threads[i].start();
        }
    }
    public void run(){
        PoolManager manager = null;
        PoolObject obj = null;
        try {
            manager = PoolManager.getInstance();
            obj = manager.getPoolObject();
            obj.execute();
        }
        finally{
            if ( obj != null ) manager.release(obj);
        }
    }
}
----8><--------------------------------------------------------------------
package badpool;
/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolManager {
    private static PoolManager manager = null;

    private int MAX = 20;
    private int count = 0;
    private java.util.Vector pool = new java.util.Vector();

    private PoolManager() {
        super();
        for(int i=0;i<MAX;i++){
            pool.addElement(new PoolObject(new Integer(i)));
        }
    }
    public static synchronized PoolManager getInstance() {
        if ( manager == null ) {
            manager = new PoolManager();
        }
        return manager;    
    }
    public synchronized PoolObject getPoolObject() {
        PoolObject obj = null;
        while( count >= MAX ) {
            try{
                Thread.sleep(1000);
            }catch(Exception e){}
            System.out.println("PoolManager : sleep... current count=" + count);
        }
        obj = (PoolObject)pool.elementAt(0);
        pool.removeElementAt(0);
        count++;
        return obj;
    }
    public synchronized void release(PoolObject obj) {
        count--;
        pool.addElement(obj);
        System.out.println("PoolManager: released ... current count=" + count);
    }
}
----8><--------------------------------------------------------------------
package badpool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolObject {
        private static java.util.Random random = new java.util.Random();
        private Integer index = null;
    
    public PoolObject(Integer i) {
        this.index = i;
    }
    public void execute() {
        // 어떤 비즈니스 로직....
        System.out.println("Thread-" + index + ": started.");
        int second = 0;
        try{
            // 5 - 15 seconds random sleep.
            second = 5 + (int)(random.nextDouble()*10);
            Thread.sleep(second*1000);
        }catch(Exception e){}
        System.out.println("Thread-" + index + ": elapsed=" + second);
    }
}
----8><--------------------------------------------------------------------

위 클래스들을 컴파일 하여 돌리면, 40개의 Thread 가 모두 동작하는 것이 아니라
20개만 수행하고 dead-lock 에 빠집니다. 왜냐면, 한정된 20 개의 PoolObject 을
동시에 40개의 Client Thread 가 요청하게 되면, 그 중 20개는 getPoolObject()을
성공하게 되어 정상적인 수행을 진행하게 되고, 나머지 20개는 synchronized lock
으로 인해 대기하게 됩니다. 한참이 지난 후 수행중이었던 20개의 Thread 가
사용하고 난 PoolObject 을 PoolManager 에게 반환(release)하려 합니다.
문제는 여기서 발생하죠. 같은 lock 객체에 의해 synchronized 가 걸려 있으니,
앞에서 getPoolObject() 을 미처 수행하지 못하고 대기하던 20개의 Thread 가
해당 lock 을 미리 점유하고 있어서, release() 메소드 내의 synchronized(lock)
블록으로 들어가지를 못하게 되는 겁니다. 
"다 사용했으나 반환을 못하고, 받지를 못했으니 나머지 20개의 Thread 는 마냥 
 기다리고만 있습니다."

물론 getPoolObject() 내에서 대부분 2-3 회 반복적으로 시도하다가 가용한 자원이
끝까지 생기지 않으면 튕켜 나가게 로직을 짜곤 합니다. 이 상황이라면 dead-lock 까지는
가지 않게 되겠지만, "끼적끼적" 겨우 하나씩 동작하게 되지요.

외견상으로는 "왜 이렇게 시스템이 갑자기 느려졌지?" 라는 형태로 나타나게 됩니다.
혹시 자신이 만든 Connection Pool 에서 Pool 최대값을 넘지 않을 때는 
잘 동작하는데, 동시에 최대값 이상의 요청이 급작스럽게 들어오고 난 이후부터
시스템이 급격하게 느려지거나 hang 이 발생한 적이 없었던가요?



아래는 고민하고 고민하여 나름대로 최적화된 모습이라 생각되는 방식을 찾아
보았습니다. 보다 더 나은 알고리즘이 있으면 조언 부탁합니다.

프로그램 설명은 각자 개인 스스로의 몫으로 돌렸으면 합니다.
주석을 이래저래 풀어 가며 테스트를 해 보시면 어떤 서로다른 결과가 나타나는지
직접 목격할 수 있을 겁니다.


----8><--------------------------------------------------------------------

package pool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolTest extends Thread{
    private int client = 0;
    public PoolTest(int n){
        this.client = n;
    }
    public static void main(java.lang.String[] args) {
        // PoolObject 의 최대값인 20 보다 많은 요청을 보내어야 테스트가 됨.
        int max = 40;
        System.out.println("Calling " + max + " threads");

        Thread[] threads = new PoolTest[max];
        for(int i=0;i<max;i++){
            threads[i] = new PoolTest(i);
            threads[i].start();
        }
    }
    public void run(){
        PoolManager manager = null;
        PoolObject obj = null;
        try {
            manager = PoolManager.getInstance();
            obj = manager.getPoolObject();
            obj.execute();
        }
        finally{
            if ( obj != null ) manager.release(obj);
        }
    }
}

----8><--------------------------------------------------------------------

package pool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolManager {
    private static PoolManager manager = null;

    private int MAX = 20;
    private int count = 0;
    private java.util.Vector pool = new java.util.Vector();

    private PoolManager() {
        for(int i=0;i<MAX;i++){
            pool.addElement( new PoolObject(new Integer(i)) );
        }
    }
    public static synchronized PoolManager getInstance() {
        if ( manager == null ) {
            manager = new PoolManager();
        }
        return manager;    
    }
    /**
     * PS: getPoolObject() 에서 파라메터로 "int from" 을 실제로는 받을 필요가
     *     없으나 어떤 Client Thread 에서 요청이 온지를 디버깅 하기 위해 넣어둔 것
     *     뿐임.
     */
     
    public synchronized PoolObject getPoolObject(int from) {
        while( count >= MAX ) {
            try{
                System.out.println("getPoolObject(from:" + from + 
                                ") : sleep... active count=" + count);
                
                // Max값을 초과한 나머지는 모두 아래 wait(timeout) 에서 대기함.
                // 아래에서 1초를 wait 하게 하지만, 실제로는 그 이전에 
                // notify() 에 의해 깨어나게 됨.
                wait(1*1000); 
                //System.out.println("awaiked. ...");

            }catch(Exception e){
                System.out.println("getPoolObject: awaiked " + e.toString());
            }
        }
        PoolObject obj = (PoolObject)pool.elementAt(0);
        pool.removeElementAt(0);
        count++;
        System.out.println("getPoolObject(from:" + from +"): return : active count=" + count);
        return obj;
    }
    public synchronized void release(PoolObject obj) {
        count--;
        pool.addElement(obj);

        //notify();
        notifyAll(); 

        // 만약 notifyAll() 을 하면 getPoolObject()에서 wait()에서 걸린
        // 모든 Thread 가 일시에 일어나게 되어 쓸데없이 전부 while 문을 동시에
        // 확인하게되고, 이는 CPU 부하를 야기할 것으로 생각되나,
        // 일부 책에서는 notify() 대신 notifyAll() 을 권장하기도 함.
        // 두가지를 모두 테스트해 보면 아주 재밌는 현상을 만날 수 있을 것임.

        System.out.println("Thread-" + obj.getIndex() + ": released :active count=" + count);
    }
}

----8><--------------------------------------------------------------------

package pool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolObject {
        private static java.util.Random random = new java.util.Random();
        private Integer index = null;
    
    public PoolObject(Integer i) {
        this.index = i;
    }
    public void execute() {
        System.out.println("Thread-" + index + ": started.");
        int second = 0;
        try{
            // 5 - 15 seconds random sleep.
            second = 5 + (int)(random.nextDouble()*10);
            Thread.sleep(second*1000);
        }catch(Exception e){}
        System.out.println("Thread-" + index + ": elapsed=" + second);
    }
    public Integer getIndex() {
        return index;
    }
}

----8><--------------------------------------------------------------------


핵심은 어떤 경우든, Thread.sleep() 을 이용하여 가용한 자원이 생길때까지 기다리게
해서는 안된다는 사실입니다.
wait() 와 notify(),notifyAll() 을 이용하여만 합니다.

NOTE: wait() 은 synchronized block 의 lock 을 해제합니다. 따라서 연이어 들오는
      쓰레드들이 sync block 안으로 들어와 wait() 부분에서 함께 waiting 하게 됩니다.

그러나, 위의 샘플은 실 프로젝트 시스템에서는 사용할 법한 소스가 아닙니다. 중요한
한가지 요소가 빠져 있습니다. 갯수에 제한이 있는 자원에 대한 요청이 엄청나게 폭주할
경우, 가용한 자원을 할당 받지 못한 요청들은 위 로직대로라면 상당히 오랫동안 
기다리게 됩니다. 이는 시스템의 hang 현상을 유발시킬 수 있는 절대적인 잠재력을
안고 있습니다. 일정한 TIME_WAIT 을 두어 일정시간을 기대려도 가용한 자원이 
여전히 생기지 않을 경우 Fail 이 일어나게 하여 튕켜 나가게 하여야만 hang 으로 
이어지지 않습니다. 

아래는 실프로젝트에서 사용할 법한 로직입니다.


package org.jsn.pool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolManager {
    private static PoolManager manager = null;

    private int MAX_RESOURCE = 20;
    private long TIME_WAIT = 2 * 1000;
    private java.util.Hashtable pool = new java.util.Hashtable();
    private java.util.Stack freeStack = new java.util.Stack();

    private PoolManager() {
        for(int i=0;i<MAX_RESOURCE;i++){
            Integer index = new Integer(i);
            pool.put( index,  new PoolObject(index) );
            freeStack.push(index);
        }
    }
    public static synchronized PoolManager getInstance() {
        if ( manager == null ) {
            manager = new PoolManager();
        }
        return manager;    
    }
    public  PoolObject getPoolObject() throws Exception {
        Integer index = null;
        long start = System.currentTimeMillis();
        synchronized(this){
            while( freeStack.empty()  ) {
                try{
                    // 나머지는 모두 아래 wait(timeout) 에서 대기함.
                    // 아래에서 1 초를 wait 하게 하지만, 실제로는 그 이전에
                    // notify() 에 의해 깨어나게 됨.
                    wait(1 * 1000);
                    
                }catch(Exception e){
                    System.err.println("getPoolObject: awaiked " + e.toString());
                }
                long end = System.currentTimeMillis();
                if ( freeStack.empty() && (end - start) >= TIME_WAIT ) {
                    throw new Exception("getPoolObject : timeout(" + TIME_WAIT + ") exceed");
                }
            }
            index = (Integer)freeStack.pop();
        }
        PoolObject obj = (PoolObject)pool.get(index);
        return obj;
    }
    public void release(PoolObject obj) {
        synchronized ( this ){
            freeStack.push(obj.getIndex());
            
            //notify();
            notifyAll(); 
            // 만약 notifyAll() 을 하면 getPoolObject()에서 wait()에서 걸린
            // 모든 Thread 가 일시에 일어나게 되어 쓸데없이 전부 while 문을 동시에
            // 확인하게되고, 이는 CPU 부하를 야기할 것으로 생각되나,
            // 일부 책에서는 notify() 대신 notifyAll() 을 권장하기도 함.
            // 두가지를 모두 테스트해 보면 아주 재밌는 현상을 만날 수 있을 것임.
        }
        //System.out.println("Object-" + obj.getIndex() + ": released.");
    }
}
----8><--------------------------------------------------------------------

필요할 경우, 위의 java.util.Stack 대신 Queue 를 사용하실 수 있습니다. 
사용하는 자원만 지속적으로 사용하고, Stack 의 저 아래에 있는 특정 자원은 한번도
사용되지 않을 것 같은 불안감(?)이 드신다면 Stack 대신 Queue 를 이용하여 다음처럼
골고루(?) 사용토록 고쳐셔도 됩니다.

package org.jsn.pool;

/*
 * Lee WonYoung
 * javaservice@hanmail.net, lwy@kr.ibm.com
 * 2000.11.21
 */
public class PoolManager {
    private static PoolManager manager = null;

    private int MAX_RESOURCE = 20;
    private long TIME_WAIT = 2 * 1000;
    private java.util.Hashtable pool = new java.util.Hashtable();
    private org.jdf.util.Queue freeQueue = new org.jdf.util.Queue();

    private PoolManager() {
        for(int i=0;i<MAX_RESOURCE;i++){
            Integer index = new Integer(i);
            pool.put( index,  new PoolObject(index) );
            freeQueue.enqueue(index);
        }
    }
    public static synchronized PoolManager getInstance() {
        if ( manager == null ) {
            manager = new PoolManager();
        }
        return manager;    
    }
    public  PoolObject getPoolObject() throws Exception {
        Integer index = null;
        long start = System.currentTimeMillis();
        synchronized(this){
            while( freeQueue.empty() ) {
                try{
                    // 나머지는 모두 아래 wait(timeout) 에서 대기함.
                    // 아래에서 1 초를 wait 하게 하지만, 실제로는 그 이전에
                    // notify() 에 의해 깨어나게 됨.
                    wait(1 * 1000);

                }catch(Exception e){
                    System.err.println("getPoolObject: awaiked " + e.toString());
                }
                long end = System.currentTimeMillis();
                if ( freeQueue.empty() && (end - start) >= TIME_WAIT ) {
                    throw new Exception("getPoolObject : timeout(" + TIME_WAIT + ") exceed");
                }
            }
            index = (Integer)freeQueue.dequeue();
        }
        PoolObject obj = (PoolObject)pool.get(index);
        return obj;
    }
    public void release(PoolObject obj) {
        synchronized ( this ){
            freeQueue.enqueue(obj.getIndex());
            
            //notify();
            notifyAll(); 
            // 만약 notifyAll() 을 하면 getPoolObject()에서 wait()에서 걸린
            // 모든 Thread 가 일시에 일어나게 되어 쓸데없이 전부 while 문을 동시에
            // 확인하게되고, 이는 CPU 부하를 야기할 것으로 생각되나,
            // 일부 책에서는 notify() 대신 notifyAll() 을 권장하기도 함.
            // 두가지를 모두 테스트해 보면 아주 재밌는 현상을 만날 수 있을 것임.
        }
       //System.out.println("Object-" + obj.getIndex() + ": released.");
    }
}
----8><--------------------------------------------------------------------


Queue.java
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=981829799

Re: LinkedList 를 이용한 Queue.java 
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=987580631


-------------------------------------------------------  
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:019-310-7324
================================================

'java' 카테고리의 다른 글

정규 표현식 기본  (0) 2012.11.23
Java 기본 변수  (0) 2011.08.25

Android System 정보 가져오기

android 2010. 11. 2. 17:27 Posted by jiddong
Android 시스템 정보를 거의다 가져온다 (ex 어플의 사용시간들,메모리 사용 량 등등등)

가저온 Line 의 이용은 알아서 하시길~

Runtime runtime = Runtime.getRuntime();
try {
Process p = runtime.exec("dumpsys");
//Process p = runtime.exec("dumpsys meminfo");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
  while ((line = br.readLine()) != null) {
Log.d("test", line);
}
        
       br.close();


} catch (Exception e) {

Log.d("Exception", e.toString());

}