반응형

스레드의 동기화(Synchronization)

자바에서는 쓰레드 자체가 어떻게 움직일지 우리가 예상할수 없으므로 다중쓰레드를 사용하다보면 예기치못한 문제를 야기할수 있다. 보여줄 예제를 설명삼아 미리 얘기해 보겠다. 여러개의 쓰레드에게 각기 다른 출력 메세지를 주고 모든 쓰레드를 작동시킨다. 문제는 한 쓰레드가 일정시간 출력을 하다가 대기모드로 전환하면 이어서 다른 쓰레드가 출력을 할것이고 쓰레드 각자가 맡은 메세지를 다 출력할수도 있고 안하고 다른 쓰레드에게 바턴이 넘어갈수도 있을 것이다. 그렇다면 화면에 출력되는 메세지는 아래처럼 말그대로 뒤죽박죽 두서가 없어질 것은 자명하다.


[강이의 자바강좌[쓰레드의 동기화[Synchronization]
]
]

동시 프로그래밍 영역에서 다중쓰레드는 말그대로 어디로 튈지 모르는 공과 같다. 어느 쓰레드가 먼저 작동할런지는 모르지만 이왕 작동했으면 처음부터 끝까지 맡은바 임무(출력 메세지)는 완수하도록 권한을 부여하는 것이 동기화(Synchronization)라 할수 있겠는데 동기화라는 말자체가 어려워서 많이 애먹는것 같다. 필자는 동기화라는 표현보다는 보호막이라는 표현이 synchronization을 이해하는데 더 도움이 될꺼라 생각한다.


자바에서 다중쓰레드가 공유하고 있는 자원을 어떤 쓰레드가 실행하고 있을때 다른 쓰레드는 접근하지 못하도록 막아주는 "보호막" 같은 장치가 바로 synchronized 라는 키워드다. 쓰는 방법은 쓰레드에서 보호막 치기를 원하는 부분을 { } 블록으로 감싸고 그 위에 synchronized(레퍼런스) 라는 타이틀을 만들어주면 된다. 다시 코드로 표현하면 아래와 같이 될것이다.

synchronized(레퍼런스)
{
   ...
   ......
}


[강이의 자바강좌]
[Synchronization]
[쓰레드의 동기화]

예제에서는 쓰레드에게 권한을 주는 용도로 쓰일 레퍼런스를 key라고 명하고 Object를 이용해 만들어 쓰고 있는데 이 권한을 같이 공유하면서 서로 쓸수 있도록 만들어야되므로 static을 붙였다. 결과에서 보듯이 한 쓰레드가 key(권한)를 얻어 출력을 시작하면 다른 쓰레드가 출력이 끝날때까지 대기했다가 key(권한)를 넘겨받아 자신이 가진 메세지를 출력하고 남아있는 쓰레드도 역시 출력이 끝날때까지 기다렸다가 본인이 가진 메세지를 key(권한)를 넘겨받은 후에야 출력을 한다. 예제에서는 쓰레드가 3개인 다중쓰레드를 작동하였는데 작업환경에 따라 어느 구문이 먼저 출력될지는 장담할수 없겠지만 어느 쓰레드건 출력을 시작했으면 처음부터 끝까지 그 구문은 완전하게 찍히는 것을 확인할수 있을 것이다.

이렇게 일정 구문을 동기화 시켜서(보호막 만들어서) 사용한다고 하여 동기화 구문(Synchronized Statements)이라고 부른다. 말나온김에 동기화 메소드(Synchronized Methods)도 공부해 보자. 말그대로 메소드앞에 그러니까 메소드 리턴타입앞에 synchronized 키워드를 붙여주면 메소드 전체를 동기화 즉 보호막 만들어서 사용할수 있다.

synchronized void print(String message )
{
   ...
   ......
}

이 경우에는 쓰레드가 해당클래스의 객체를 공유하도록 만들어야 정상적으로 작동된다. 이렇게 설명하고 끝내면 비난(?)이 빗발칠걸로 예상되므로 동기화 메소드에 관련된 예제도 아래에 준비하였으니 코드를 보면서 연구해보기 바란다. 결과는 위와 같을 것이나 이번에는 구문이 아닌 메소드를 동기화시켰다는게 차이점이다.


예제를 간략하게 설명하자면 클래스의 레퍼런스로 key를 만들어 쓰레드끼리 공유해서 쓰도록 하고 있고 쓰레드의 실행블록인 run( ) 메소드에서 동기화시킨 print( ) 메소드를 key 레퍼런스를 이용해 불러서 쓰면 특정 쓰레드가 해당블록 실행시 다른 쓰레드가 관련 메소드에 들어오지 못하도록 보호막을 쳐준다. key의 데이터형이 지금 클래스명이라는 것을 여러분이 알아챘기 바란다. 예제를 곰곰히 이리저리 씹어보면 어느순간(?) 이해가 되기 시작할 것이다. 생성자(constructor)를 이용하면 코드가 훨씬 더 간결해질 것이나 이해를 돕고자 기존 예제를 최대한 건드리지 않는 쪽으로 가닥을 잡아서 만든 까닭에 소스가 좀 길다. 마음에 안들면 생성자를 이용해서 여러분이 원하는데로 응용해 보기 바란다.+ 제발 해봐라.ㅎㅎ 또한 synchronized 키워드를 메소드에서 제하고 다시 실행을 하여 무슨 차이가 있는지 비교하기 바란다.^^

쓰레드의 동기화는 동시 프로그래밍 영역에서 매우 유용하게 쓰이는 부분이다. 이보다 더 간단할수는 없다라는 심정으로 쓰레드의 Synchronization에 관한 가장 기본적인 내용만이라도 확실하게 기억하기를 바라면서 본 강좌를 아주 심플하게 구성하였으니 더도 덜도말고 최소한 오늘 배운 내용은 확실하게 습득하기 바란다.^^


반응형
반응형

주석을 제대로 달면 소스 분석이 쉬워지고 유지보수가 쉽습니다. 자바를 위한 소스 문서화 솔루션인 JAVA DOC을 이용해서 문서를 만드는법을 알아보죠. 우선 한번 JAVA Documnet가 만들어지는 과정을 한번 살펴 보죠. 소스 주석 설명은 나중에 나옵니다. 일단 만드는 과정만 보세요.

JAVA DOC 주석을 사용한소스

/**
* Study.java2002-07-25
* 루프와 제귀호출 성능 비교
* @author wonjin
*/
public class Study {

public static void main(String[] args) {
long temp; //수행시간 계산을 위한 임시변수
temp = System.currentTimeMillis();
for (int i = 0; i < 120000; i++)
factorial1(200);
System.out.println(System.currentTimeMillis() - temp);
temp = System.currentTimeMillis();
for (int i = 0; i < 120000; i++)
factorial2(200);
System.out.println(System.currentTimeMillis() - temp);
}

/**
* Method factorial1.팩토리알을 구한다, 루프 사용
* @param num 구 할 수
* @return long 결과
*/
public static long factorial1(int num) {
long result = 1;
while (num > 1) {
result *= num--;
}
return result;
}
/**
* Method factorial1.팩토리알을 구한다, 제귀적호출
* @param num 구 할 수
* @return long 결과
*/
public static long factorial2(int num) {
if (num < 2)
return 1;
else
return num * factorial2(num - 1);
}
}

이렇게 JAVA DOC주석 방식을 이용해서 코딩을 합니다. 그런 다음에는 javadoc을 이용해서 문서를 만들면 됩니다. javadoc은 J2SDK가 설치되어있는 bin 디렉토리에 있습니다. 위 소스가 있는 디렉토리로가서.

e:\ide\eclipse\workspace\study>javadoc study.java

이렇게 실행을 하면 도큐먼트가 만들어 집니다.

주의:bin디렉토리가 시스템 패스에 잡혀 있어야 합니다.

javdoc study.java -d e:\doc 이런 식으로 -d 옵션을 이용해서 만들경로를 지정 할 수 있습니다. 어떤것들이 만들어 졌는지 볼까요?

많이 만들어 졌네요. 하지만 index.html만 실행하면 소스에대한 문서를 볼수 있습니다.

JAVA DOC으로 만든 문서

Class Study

java.lang.Object
  |
  +--Study

public class Study
extends java.lang.Object

Study.java2002-07-25 루프와 제귀호출 성능 비교

Author:
wonjin

Constructor Summary
Study()
           
 
Method Summary
static long factorial1(int num)
          Method factorial1.팩토리알을 구한다, 루프 사용
static long factorial2(int num)
          Method factorial1.팩토리알을 구한다, 제귀적호출
static void main(java.lang.String[] args)
           
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

Study

public Study()
Method Detail

main

public static void main(java.lang.String[] args)

factorial1

public static long factorial1(int num)
Method factorial1.팩토리알을 구한다, 루프 사용

Parameters:
num - 구 할 수
Returns:
long 결과

factorial2

public static long factorial2(int num)
Method factorial1.팩토리알을 구한다, 제귀적호출

Parameters:
num - 구 할 수
Returns:
long 결과

 

자 만드는법은 쉽죠? 이제 주석에 대해 알아 볼까요?

/**
* Study.java2002-07-25
* 루프와 제귀호출 성능 비교
* @author wonjin
*/

일반 주석 방식과는 조금 다릅니다. /**로 시작해서 */로 끝나죠 그리고 주석 내용 앞에는 * 가 꼭 있어야 합니다. 예약어 (@author 와같은 @시작하는)를 사용하지 않은 문장은 그대로 보여집니다.

public class Study
extends java.lang.Object

Study.java2002-07-25 루프와 제귀호출 성능 비교

하지만, 예약어를 사용한 문장은 구분 되어서 보여지죠.

Author:
wonjin
 
이제 메소드에 대한 JAVA DOC 주석을 볼까요?

/**
* Method factorial1.팩토리알을 구한다, 루프 사용
* @param num 구 할 수
* @return long 결과
*/

factorial2

public static long factorial2(int num)
Method factorial1.팩토리알을 구한다, 제귀적호출

Parameters:
num - 구 할 수
Returns:
long 결과

 

간단하네요. 일반적인 설명, @param 변수이름 설명, @return 리턴형 설명. 메소드에 대한 예약어는 더 있습니다. @throws 예외형 설명. 이 외에도 다른 예약어들이 있고 이 예약어들을 조합해서 문서를 만들면 됩니다.

더 자세한 내용을 알고 싶으면 http://java.sun.com/j2se/javadoc/index.html 에 방문해 보세요.

 

JAVA DOC Tag List

Overview Tags
@see
@since
@author
@version
{@link}
{@linkplain}
{@docRoot}

 

Package Tags
@see
@since
@deprecated
@serial
@author
@version
{@link}
{@linkplain}
{@docRoot}

 

Class/Interface Tags
@see
@since
@deprecated
@serial
@author
@version
{@link}
{@linkplain}
{@docRoot}

An example of a class comment:

/**
 * A class representing a window on the screen.
 * For example:
 * <pre>
 *    Window win = new Window(parent);
 *    win.show();
 * </pre>
 *
 * @author  Sami Shaio
 * @version %I%, %G%
 * @see     java.awt.BaseWindow
 * @see     java.awt.Button
 */
class Window extends BaseWindow {
   ...
}

 

Field Tags
@see
@since
@deprecated
@serial
@serialField
{@link}
{@linkplain}
{@docRoot}
{@value}

An example of a field comment:

    /**
     * The X-coordinate of the component.
     *
     * @see #getLocation()
     */
    int x = 1263732;

 

Method/Constructor Tags
@see
@since
@deprecated
@param
@return
@throws and @exception
@serialData
{@link}
{@linkplain}
{@inheritDoc}
{@docRoot}

An example of a method doc comment:

    /**
     * Returns the character at the specified index. An index 
     * ranges from <code>0</code> to <code>length() - 1</code>.
     *
     * @param     index  the index of the desired character.
     * @return    the desired character.
     * @exception StringIndexOutOfRangeException 
     *              if the index is not in the range <code>0</code> 
     *              to <code>length()-1</code>.
     * @see       java.lang.Character#charValue()
     */
    public char charAt(int index) {
       ...
    }

 

반응형
반응형

요새 산출물로 자바 도큐먼트를 만드는 경우가 많다.


개발하기도 바뿐데 코딩하면서 주석도 달기 귀찮긴 하지만 


워드로 산출물을 만드는것보다 훨씬 경제적이고 덜 노가다? 가 필요해서 좋은것 같다.


기본적으로 자바문서를 만들면 패키지 까지는 주석이 달려나올 수가 없다.


어느정도 노가다가 좀 필요한데 방법을 설명 해보기로 한다.


참고로 자바문서를 위해 주석은 

/**  이것은 클래스 **/

class Sample{

/** 변수 */

private String name;

}

 이런식으로 클래스나 메소드 변수명 위에 써주면 된다.


이제 부터 문서도구 만드는 예제를 설명하겠다.


1.자바 프로젝트 생성



3개의 패키지를 만들고 각각의 패키지에 클래스를 만든다.


2.패키지 설명 파일 생성

각각의 패키지에서 일반 파일을 생성하고 이름을 package-info.java 로 만든다.

패키지 우클릭 - New - File - package-info.java 생성.



3.패키지 수석달기

패키지 마다 package-info.java 파일을 열고 아래와 같이 해당 패키지명을 입력한다. 

각각의 파일들에 다 입력한다.



4.자바문서생성



패키지 단위로 설명이 나오는것을 확인 할 수 있다.


질문은 댓글 환영합니다~

반응형

'Code Inspection' 카테고리의 다른 글

PMD eclipse  (0) 2013.06.24
checkstyle rule  (0) 2013.05.22

+ Recent posts