태그 보관물: java

자바 CountDownLatch를 이용한 동시성 높이기..

각종 환경에서 성능을 높이기 위해서 취하는 방법이 멀티 프로세스와 멀티 쓰레드이다. 자바에서는 성능을 높이기 위해서 기본적으로 멀티 쓰레드의 형태를 취하고 있다. 물론, JNI를 사용해서 Native의 프로세스를 띄울 수 있기도 하다. 자바의 기본 패키지중에서 쓰레드를 사용해서 동시성을 극대화 시키는 각종 자료구조와 클래스들은 java.uti.concurrent 패키지를 확인해 보면 알 수 있다.

수학적인 계산을 제외한, 거의 모든 컴퓨터 성능이슈는 느린 I/O 처리를 어떻게 빠르게 처리하냐가 주된 관심사가 아닐까 한다. 

그래서, 많이 쓰이는 쓰레드의 형태를 살펴보면..
1. 잡을 개별 쓰레드로 위임한다.
2. 잡을 개별 쓰레드가 처리하고 결과를 취합해서, 취합된 결과를 기준으로 처리를 한다.

보통은, 위의 1.번으로 처리를 하는 경우가 많지만, 간혹, 2.번의 형태가 필요한 경우가 발생한다. 이 경우에 보통은 메인 쓰레드에서 잡 쓰레드를 생성하고, 자신은 wait하고 있다가 notify를 받는 구조를 많이 취하게 된다. 바로 이런 형태로 2.번의 상황을 처리할 수 있게 해 주는 클래스가 CountDownLatch이다.

자, 간단하게 예제를 살펴보자.

package net.sjava.example.countdownlatch;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
	static final int max = 10;
	/**
	 * 단일 쓰레드 테스트
	 */
	public static void testSingle() throws Exception {
		long start = System.currentTimeMillis();
		for (long i = 0; i < max; i++) {
			Thread.sleep(1000);
		}

		long elapsedTime = System.currentTimeMillis() - start;
		System.out.println("testSingle elapsed time -> " + elapsedTime);
	}

	/**
	 * CountDownLatch 테스트
	 */
	public static void testCountDownLatch() throws Exception {
		final CountDownLatch latch = new CountDownLatch(max);

		long start = System.currentTimeMillis();
		for (long i = 0; i < max; i++) {
			new Thread(new Worker(latch)).start();
		}

		latch.await();
		long elapsedTime = System.currentTimeMillis() - start;
		System.out.println("testCountDownLatch elapsed time -> " + elapsedTime);
	}

	/**
	 * Job 쓰레드
	 */
	static class Worker implements Runnable {
		private CountDownLatch latch;

		public Worker(CountDownLatch latch) {
			this.latch = latch;
		}

		@Override
		public void run() {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			} finally {
				if (this.latch == null)
					return;

				latch.countDown();
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		testSingle();
		testCountDownLatch();
	}
}

위의 코드의 결과는 아래와 같아서, 너무 극단적이긴 하지만, CountDownLatch의 사용을 위한 쉬운 예가 될 것이다.

testSingle elapsed time -> 10,000
testCountDownLatch elapsed time -> 1,004

Java에서 파일 이름의 유효성 체크 및 이름 바꾸기..

기본적으로 OS에서는 특수 캐릭터가 예약되어 있어, 파일 이름으로 사용할 수 없다.

그래서, 프로그램에서 파일 관련 작업을 하기 전에, 파일 이름에 대한 유효성 체크와 파일 이름에 대한 변환이 필요한 경우가 있다. 위에 대한 내용은, http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words나 http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx#naming_conventions에서 OS별로 예약되어 있는 캐릭터와 파일의 길이를 확인할 수 있다.

아래는 위의 MSDN 링크(윈도우 OS)에 나와 있는 대표적인 캐릭터이고, 추가적인 문자열은 위 링크에서 확인할 수 있다.

< (less than)
> (greater than)
: (colon)
” (double quote)
/ (forward slash)
\ (backslash)
| (vertical bar or pipe)
? (question mark)
* (asterisk)

아래는 자바로 위의 제약조건에 대한 확인을 제공하는 클래스이다.

import java.util.regex.Pattern;
public class FileNameUtil {
	// 파일이름 확인..
	static final String ILLEGAL_EXP = "[:\\\\/%*?:|\"<>]";

	/**
	 * 파일 이름이 유효한지 확인한다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일의 이름, Path를 제외한 순수한 파일의 이름.. 
	 * @return
	 */
	public static boolean isValidFileName(String fileName) {
	    if(fileName == null || fileName.trim().length() == 0)
	    	return false;

		return !Pattern.compile(ILLEGAL_EXP).matcher(fileName).find();
	}

	/**
	 * 파일 이름에 사용할 수 없는 캐릭터를 바꿔서 유효한 파일로 만든다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일 이름, Path를 제외한 순수한 파일의 이름..
	 * @param replaceStr 파일 이름에 사용할 수 없는 캐릭터의 교체 문자
	 * @return
	 */
	public static String makeValidFileName(String fileName, String replaceStr) {
	    if(fileName == null || fileName.trim().length() == 0 || replaceStr == null)
	    	return String.valueOf(System.currentTimeMillis());		

	    return fileName.replaceAll(ILLEGAL_EXP, replaceStr);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

	    String c = "!\"#$%&(){}@`*:+;-.<>,^~|'[]akdfsjhex.txt"; 

	    System.out.println("bbbb --> " + isValidFileName("abcde.jpg"));
	    System.out.println("bbbb --> " + isValidFileName(c));
	    System.out.println("bbbb --> " + makeValidFileName(c, "_") );        
	}
}

위 코드는 자바 환경인 안드로이드에서도 사용할 수 있다.

wget으로 java sdk 다운로드 하기..

wget은 리눅스/유닉스 기반에서 http, https 그리고 ftp상에 있는 컨텐츠를 쉽게 다운로드 해 주는 간단한 유틸리티 프로그램이다. 리눅스/유닉스에서는 기 설치되어 있거나, 쉽게 찾을 수 있지만.. 윈도우용으로는 http://users.ugent.be/~bpuype/wget/ 에서 다운로드 받아서 사용할 수 있다. 

보통, 리눅스/유닉스 기반의 서버들은 윈도와 다르게, GUI 환경을 사용하지 않는 것이 일반적이어서, 필요한 라이브러리나 어플리케이션을 다운로드하고 설치하기에는 wget이 정말 유용하다.

자 본론으로, java sdk를 wget으로 설치하는 방법에 대해서 알아보자..

1. java.sun.com에 접속해서 다운로드할 java 버전을 확인하고, 다운로드를 시작한다. 

 – 아래에서는 Linux x86버전의 sdk를 선택했습니다.

2. 다운로드를 시작하고, 다운로드 창에서 Get Link를 통해서 실제로 다운로드하는 바이너리의 위치를 복사한다.

3. wget으로 복사된 Link의 java sdk를 다운로드 한다. 

 – 실행

[xxxxx@justin ~]$ wget http://download.oracle.com/otn-pub/java/jdk/6u35-b10/jdk-6u35-linux-i586.bin?AuthParam=1348550746_bb8a619fac178661a342f75b3362ceea

 – 다운로드 결과

–2012-09-25 05:23:56–  http://download.oracle.com/otn-pub/java/jdk/6u35-b10/jdk-6u35-linux-i586.bin?AuthParam=1348550746_bb8a619fac178661a342f75b3362ceea
Resolving download.oracle.com… 207.109.73.49, 207.109.73.27
Connecting to download.oracle.com|207.109.73.49|:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 71758261 (68M) [application/octet-stream]
Saving to: “jdk-6u35-linux-i586.bin?AuthParam=1348550746_bb8a619fac178661a342f75b3362ceeaâ€

100%[===========================================================>] 71,758,261  9.95M/s   in 5.8s

2012-09-25 05:24:02 (11.8 MB/s) – “jdk-6u35-linux-i586.bin?AuthParam=1348550746_bb8a619fac178661a342f75b3362ceeaâ€

– 확인

[xxxxx@justin ~]$ ll
total 70080
-rw-rw-r– 1 ec2-user ec2-user 71758261 Sep  5 16:54 jdk-6u35-linux-i586.bin?AuthParam=1348550746_bb8a619fac178661a342f75b3362ceea

4. 일반적인 형태의 sdk로 파일이름 변경..

[xxxxx@justin ~]$ mv jdk-6u35-linux-i586.bin\?AuthParam\=1348550746_bb8a619fac178661a342f75b3362ceea jdk-6u35-linux-i586.bin
[xxxxx@justin ~]$ ll
total 70080
-rw-rw-r– 1 ec2-user ec2-user 71758261 Sep  5 16:54 jdk-6u35-linux-i586.bin

자, 위의 과정으로 그 동안 서버에서 java sdk 설치를 위해서 귀찮게, 다운로드 해서 scp나 filezila같은 툴로 업로드 했던 과정을 줄여줄 수 있겠다.. ^^