** java.util.Calendar는 추상 클래스이다.

 

Date 클래스의 대부분 밀레니엄 버그로현재 Deprecated 된 것들이지만 아직 유효한 것들도 있다. 하지만Calendar클래스를 사용할 것을 권장 한다.

 

또한Calendar클래스는 일계산, 주별계산, 월별계산, 년별계산이 가능하기 때문에 달력에 관한 거의 모든 처리를 쉽게 할수 있다. 반면 Date 클래스는 시간, 일 에 대한 계산을 해주기 때문에 주별계산, 월별계산, 년별 계산등을 직접 구현해 줘야 한다.

 

따라서 Date클래스에 대한 구체적인 논의의 가치가 별로 없지만 아직도 기존 소스에서 Date의 사용하고 있으므로 정리한다.

 

Java.util.Date.getTime()January 1, 1970, 00:00:00 GMT”이후부터 지금까지 흐른 시간을 밀리세컨드로 환산한 값을 반환한다는 점에 주목해야 한다. 따라서 반환된 값에대해서는 프로그램 로직으로 직접 계산해서 사용 해야한다. 그리고 java.util.Date는 항상 1900을 달고 다녀야 한다. Java.util.Date.getYear() 메서드는 1900년으로 부터의 년수를 반환하므로  지금의 연도를 표현하려면 1900을 더해줘야하고 생성자에서 년도는 2001 에서 1900을 빼줘야 한다.그리고 달도 0부터 시작되며 생성자에서는 -1 해줘야 한다.

 

Calendar 객체 생성

일반적으로

    GregorianCalendar now = new GregorianCalendar();

와 같이 오브젝트를 생성하여 사용하기도 하지만  Calendar차 후에 어떤 종류의 Calendar를 담을수 있도록 Calendar 추상 클래스의 변수를 사용하는 것을 다음과 같이 권장한다.

    Calendar now = new Calendar .getInstance();

 

 

Calendar & Time zone

TimeZone 클래스를 Calendar클래스와 함께 이용하게되면 해당 지역의 시간으로 설정 할 수있습니다.

 

    // 기본 Time Zone

    TimeZone tz = Calendar.getInstance().getTimeZone();

 

    // 런던의 시간을 기준으로 Calendar를 설정한다.

    TimeZone timeZone = TimeZone.getTimeZone("Europe/London");

    Calendar calendar = new Calendar.getInstance();

    calendar.setTimeZone(timeZone);

 

TimeZone에 대한 ID는 "static String[] getAvailableIDs()" API로 확인 할 수 있다.

 


TimeZone

일반 적으로 현재 시스템에서의 날짜는 GregorianCalendar Calendar클래스를 이용하여 다음과 같이 현재의 시간 정보를 구할 있다.

 

       GregorianCalendar now = new GregorianCalendar();

       Calendar now = new GregorianCalendar();

       Calendar now = Calendar.getInstance();

       ** 마지막으로 now 인스턴스를 구하는 것을  추천한다.

 

Calendar객체를 재설정 하고자 하는 경우의

   now.set(Calendar.YEAR, 1972);

   now.set(Calendar.MONTH, Calendar.MAY);

now.set(Calendar.DATE, 20);

 

 하지만 세계 각국의 시간정보를 구하기 위해서는 TimeZone클래스를 이용하여 설정 작업을 해야한다.

       Calendar now = Calendar.getInstance();

       now.setTimeZone(TimeZone.getTimeZone("US/Mountain"));

 

Java.util.Date 인스턴스는 1970 1 1 이후 부터의 지난 시간을 밀리세컨드로 환산한 절대 값을 갖는다. 그러나 Calendar Date 정보를 현재 시스템(또는 새로 설정한) Locale 맞는 날짜 정보로 변환해 준다.

 

다음 코드는 동일한 Date 두개의 다른 Time Zone 테스트 하는 코드이다.

 

public class DateTest {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

 

              Date date = new Date();

 

              Calendar now = Calendar.getInstance();

 

              // 서울  : Asia/Seoul

              // 멜번 : Australia/Melbourne

              TimeZone AUML = TimeZone.getTimeZone("Australia/Melbourne");

              Calendar aus = Calendar.getInstance(AUML);

              aus.setTime(date);

              System.out.println("호주/멜번 : " + aus.get(Calendar.YEAR) + "-" + aus.get(Calendar.MONTH) + "-" 

                       + aus.get(Calendar.DATE) + " "   + aus.get(Calendar.HOUR) + ":" 

                       + aus.get(Calendar.MINUTE) + ":" + aus.get(Calendar.SECOND));

 

              TimeZone KOSL = TimeZone.getTimeZone("Asia/Seoul");

              Calendar kor = Calendar.getInstance(KOSL);

              kor.setTime(date);

              System.out.println("한국/서울 : " + kor.get(Calendar.YEAR) + "-" + kor.get(Calendar.MONTH) + "-" 

                       + kor.get(Calendar.DATE) + " "   + kor.get(Calendar.HOUR) + ":" 

                       + kor.get(Calendar.MINUTE) + ":" + kor.get(Calendar.SECOND));

 

       }

 

}

 

 

 

결과

호주/멜번 : 2013-10-1 3:15:33

한국/서울 : 2013-10-1 1:15:33

 

'Java > Core Utilities' 카테고리의 다른 글

Preferences & PreferenceChangeListener  (0) 2013.02.09
Properties  (0) 2013.02.09
Collection, Map 클래스의 사용시 성능과 계층구조  (0) 2013.02.09
Collections과 정렬  (0) 2013.02.09
Timer, TimerTask & TimeZone  (0) 2013.02.09
Posted by Steven J.S Min
,

1. String

1). 기본형 타입으로 문자열을 선언하면 Literal Pool 문자열이 하나하나 나눠져 저장되어 다시 문자를 사용한다면 Literal Pool 저장되었던 문자를 다시 사용한다.

    》ex) String a = "abc"; -> abc Literal Pool 저장

      2). 참조형 타입을 문자열을 선언하면 Heap영역에 문자열이 저장된다.

    》 ex) String a = new String("abc); -> a Stack영역에 있고 "abc" Heap 저장되며 "abc" 저장된 Heap영역의 주소값이 변수a 저장된다.

3). 비교

    》기본형은 == 비교

    》참조형은 equals 비교

    》equalsIgnoreCase 메소드는 영문자를 대소문자 구분없이 비교

 

 

2. StringBuffer StringBuilder의 차이점

StringBuffer 멀티스레드 환경에서 안전

StringBuilder 멀티스레드 환경에서 불안전 하므로 스레드 환경에 따라 사용여부를 구분한다.

두 클래스는 거의 비슷하지만 단지 차이점이 있다면 클래스안에 StringBuffer synchronized 라는 구문이 있고(멀티스레드 환경에서 안전) StringBuilder 에는 없다

 그러므로 StringBuilder 가 조금 아주 미약하게나마 성능이 좋다 하는데 안정성을 위해 StringBuffer 를 사용하는 걸 추천한다

 

3. StringBuffer,StringBuilder String의 차이점

1). StringBuffer StringBuilder 문자열 수정이 메모리 효율적으로 좋다.

2). String 문자열 수정 메모리 효율이 비교적 좋지 않다

 

4. String, StringBuffer StringBuilder의 성능

StringStringBuffer보다는 367, StringBuilder보다는 512배 빠르고...

메모리사용량은 StringStringBuffer, StringBuilder보다 3,390배 더 사용한다네요 ^^

결론적으로 String보다는 StringBuilder 사용이 좋을것같네요 ^^

 

 

출처 : http://wonsstory.tistory.com/36

'Java > Working with Text' 카테고리의 다른 글

NumberFormat, ChoiceFormat, DateFormat, SimpleDateFormat  (0) 2013.11.01
java.util.Scanner  (0) 2013.10.31
Posted by Steven J.S Min
,

멀티쓰레드에서는 여러 쓰레드에서 같은 프로세스 내의 자원을 공유해서 작업을 하기 때문에 자칫하면 각각의 쓰레드가 하나의 자원에 접근 제어를 하게 되어 서로의 작업에 영향을 주게 있음.

주의할 , 쓰레드가 교착상태(dead lock) 빠질 있음

 

교착상태(Dead lock)

하나의 이상의 쓰레드가 lock 상태에서 서로 lock 풀리기를 기다리는 상황

교착 상태에서는 작업이 진행되지 않고 쓰레드는 작업을 영원히 기다리는 상황이 .
그리하여 자바에서는 stop(), suspend(), resume() 같은 쓰레드의 상태를 변경하는 메서드들이 deprecated 되어짐.

만일 객체에 lock 상태에서 쓰레드가 종료되거나 정지 된다면, 객체를 사용하기 위해 대기중인 쓰레드들은 영원이 기다려야 되는 교착상태에 처하게 . 그리하여 쓰레드들 종료시킬 때에는 작업중인 객체의 lock 풀고, 작업 중에 변경했던 데이터를 작업이전의 상태로 돌려놓아야 .

 

 

package thread1;

 

public class MainClass {

 

       /**

        * @param args

        * @throws InterruptedException

        */

       public static void main(String[] args) throws InterruptedException {


              ManageThread mt = new ManageThread();

              mt.startThread();


              Thread.sleep(100);


              mt.stopThread();

       }

 

}

 

  
 

package thread1;

 

public class ManageThread {

 

       TestThread xxx = new TestThread("첫번째 Thread");

       TestThread yyy = new TestThread("두번째 Thread");

       Thread t1 = new Thread(xxx);

       Thread t2 = new Thread(yyy);

 

       public void startThread() {

              t1.start();

              t2.start();

       }

 

       public void stopThread() {

              xxx.stopRunning();

              yyy.stopRunning();

       }

 

}

 

  

 

package thread1;

 

public class TestThread implements Runnable {

      

       private boolean timeToStop = false;

       String name;

       int cnt = 0;

 

       TestThread(String name) {

              this.name = name;

       }

 

       @Override

       public void run() {

              while (timeToStop != true) {

                     System.out.println(name + ":" + cnt++);

              }

       }

 

       public void stopRunning() {

              timeToStop = true;

       }

      

}

 

이 예제를 수행해 보면 xxx yyy Thread가 각각 경쟁하면서 수행되는 것을 알 수 있다. 한 순간에는 하나의 Thread만이 수행된다. 따라서 적당한 시간을 분배받아서 Thread가 수행되다가 다른 Thread에게 우선권을 넘긴다. 그러면 우선권을 받을 Thread가 수행되는 것이다.


이런 방식을 통하여 여러 thread가 한꺼번에 수행될 수 있다. Java에서는 preemptive(선점형) 방식으로 Thread를 수행시킨다. 이 방식은 Thread에게 일률적으로 일정한 시간을 배당하는 기존의 방식(cooperative)과는 다르다. preemptive방식은 우선순위(priority)를 각 Thread에게 배정하고 우선순위가 높은 Thread CPU를 할당한다. 따라서 어떤 Thread가 높은 순위의 우선순위를 배정받은 후 그 순위가 바뀌지 않는다면 그 Thread를 계속 수행하게된다. 따라서 각 Thread의 우선순위를 변경해줌으로써 골고루 Thread가 배정되도록 해주어야 하는데 이 일은 Thread Scheduler가 담당한다(우리가 알 바 아니다).

위에서 살펴본 Thread.sleep()는 자신의 Thread를 잠깐 멈추고 자기보다 낮은 순위의 다른 Thread에게 우선권을 넘긴다.

여기서 참고로 알아둘 method가 있다. Thread.currentThread()라는 method인데 이를 호출하면 현재 수행되고 있는 Thread reference를 얻을 수 있다. 또한 Thread.currentThread().getName()하면 그 Thread의 이름도 알 수 있다. 참고하기 바란다.


만약 은행권 처럼 계좌금액에 동시에 + 하거나 - 하기도 전에 다른 스레드가와서 그 금액을 보고 돈을 판단하는 문제가 생기는 경우는 그럼 어떻게 할 것인가?

 

 

package thread2;

 

public class ThreadProblem {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              ManageThread mt = new ManageThread();

              mt.startThread();

 

       }

 

}

 

 
 

package thread2;

 

public class ManageThread {

 

       SharedData sd = new SharedData();

       TestThread xxx = new TestThread("첫번째 Thread", sd);

       TestThread yyy = new TestThread("두번째 Thread", sd);

       Thread t1 = new Thread(xxx);

       Thread t2 = new Thread(yyy);

 

       public void startThread() {

              t1.start();

              t2.start();

       }

 

}

 

  

 

package thread2;

 

public class TestThread implements Runnable {

 

       String name;

       SharedData sd;

 

       TestThread(String name, SharedData sd) {

              this.name = name;

              this.sd = sd;

       }

 

       public void run() {

              System.out.println(name + " push data : " + sd.push('a'));

              System.out.println(name + " push data : " + sd.push('b'));

              System.out.println(name + " push data : " + sd.push('c'));

              System.out.println(name + " pop data : " + sd.pop());

              System.out.println(name + " pop data : " + sd.pop());

              System.out.println(name + " pop data : " + sd.pop());

       }

 

}

 

 

 

package thread2;

 

public class SharedData {

 

       int stackPointer = 0;

       char[] stack = new char[100];

 

       public synchronized char push(char data) { // synchronized method

              stack[stackPointer] = data;

              doForALongJob();

              stackPointer = stackPointer + 1;

              return data;

       }

 

       public char pop() {

              synchronized (this) { // synchronized block

                     stackPointer = stackPointer - 1;

                     doForALongJob();

                     return stack[stackPointer];

              }

       }

 

       public void doForALongJob() {

              for (long i = 0; i < 5000000; i++) {

              }

       }

 

}

 

 

 

sychronized 2가지 방식을 보여주었다.  메소드에 선언하는거랑 메소드내부에서 묶는거랑...
위처럼 synchronized 키워드를 이용하면 간단히 동기화 할 수 있다...( 유닉스 스레드락보다 훨씬 간단하다 :) )
참고로 메소드에 거는것보다 블럭으로 만드는게 성능상으로 더 좋다. 메소드에 걸면..  더 많은 과정을 거치게 된다.

wait() and notify()

synchronized만 있으면 Thread의 모든 문제가 해결될까? 그랬으면 얼마나 좋을까? 하여간 해결해야 할 문제가 하나 더 있다.

위에서 살펴보았던 stack의 예제를 좀 더 생각해 보자. 만약 stack이 비어있는 상태에서 pop()가 수행되었다면 어떻게 될 것인가? 이 문제는 synchronized로는 도저히 해결할 수 없는 문제이다(data가 없다고 해서 pop() 호출을 그냥 없었던 일로 해서는 안 된다. pop()가 호출되었다면, stack에서 반드시 data를 하나 꺼내야 한다).

이 문제를 어떻게 해결하면 좋을까? 또 생각해보자(이 생각은 사실 wait(), notify()를 설명할 때 단골 손님으로 등장하는예이다).

여러분이 서울역에서 잠실까지 가려고 택시를 탔다고 생각하자. 잠실까지 가는 동안 5분마다 운전기사에게 "여기 잠실이에요?"라고 물을 사람은 아마 아무도 없을 것이다. 대부분 타자마자 "잠실 갑시다."라고 말한 후 잠을 자거나 딴 생각할 것이다. 잠실에 도착하면 기사가 알아서 "잠실입니다."라고 말해줄 것이다. 이건 매우 합리적인 일이다.

, 이 예를 stack에 적용해보자. 어떤 Thread stack에서 pop()을 했는데 stack이 비어 있었다. 그렇다면 하는 수 없이 이 Thread block상태(대기상태)가 된다. , stack data push될 때까지 기다리게 된다. 이것은 잠실에 도착할 때까지 손님이 잠자는 것과 같은 이치이다.

  후에 stack data가 들어오게 되면 block되어 있던 Thread에게 data가 왔다는 신호를 해준다. 이것은 운전기사가 잠자고 있는 손님에게 잠실에 도착했다는 신호를 보내는 것과 같다. 그러면 대기중인 Thread stack에서 data pop할 수 있는 상태가 되는 것이다.

Java Thread에서도 지금 설명한 방식이 사용된다. 그때 사용되는 method wait(), notify()이다.

 

출처: http://sinily.tistory.com/16

 

 

 

 

 

 

'Java > Threads' 카테고리의 다른 글

Controlling Thread Status  (0) 2013.02.07
Thread & Runnable  (0) 2013.02.07
Posted by Steven J.S Min
,

Thread Status

 

상태에 대해서 설명해드리자면

New 스레드의 객체가 생성된 상태를 말합니다

Thread 클래스를 상속받거나 Runnable 인터페이스를 구현한 클래스를 new(생성한) 상태입니다

Runnable 생성된 스레드에 start 메소드를 호출했을때의 상태입니다

스레드가 실제로 실행되지는 않았지만 준비단계에 있는 것을 말합니다

Running 스레드가 스케쥴러에 의해서 실제로 동작하고있는 상태입니다

run 메소드가 실행되고 있겠죠?

Blocking Running 상태이던 스레드가 run 메소드를 모두 마치지 않고 중간에 중지된 상태입니다

입출력이나 인터럽트의 요청이 있을 경우 발생합니다 sleep, yield, join 메소드 호출시에도 발생하구요

Dead Running 상태이던 스레드가 run 메소드의 작업을 모두 처리하고 제거되는 상태입니다

 

생성과 실행은 이미 살펴봤으니 Blocking 관련된 메소드들에 대해서 알아봐야겠군요

언급했던 세가지 메소드 sleep, yield, join 메소드를 공부해봅시다

 

세가지 메소드를 간단히 요약하면 이렇습니다

  • sleep 메소드는 지정한 시간만큼 스레드를 Blocking 합니다
  • yield 메소드는 우선순위가 동일한 스레드에게 양보하도록 유도하는 메소드입니다
  • join 메소드는 메소드를 호출한 스레드가 종료될때까지 스레드를 생성한 스레드를 Blocking 합니다


그럼 실제로 sleep 메소드를 사용하는 소스코드를 작성해보겠습니다

 

package thread;

 

public class SleepTest implements Runnable {

       private int dan;

 

       /**

        * @param args

        */

       public SleepTest(int dan) {

              this.dan = dan;

       }

 

       @Override

       public void run() {

              long sleepTime = (long) (Math.random() * 500);

              System.out.println(dan + "단은 " + sleepTime + "만큼 sleep 실행");

              try {

                     Thread.sleep(sleepTime);

              } catch (InterruptedException e) {

                     e.getMessage();

              }

              for (int i = 1; i <= 9; i++) {

                     System.out.println(dan + ":" + dan + " * " + i + " = " + dan * i);

              }

 

       }

 

} 

 

 

 

package thread;

 

public class MainClass {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              Thread thread2 = new Thread(new SleepTest(2));

              Thread thread3 = new Thread(new SleepTest(3));

              Thread thread4 = new Thread(new SleepTest(4));

              Thread thread5 = new Thread(new SleepTest(5));

              Thread thread6 = new Thread(new SleepTest(6));

              thread2.start();

              thread3.start();

              thread4.start();

              thread5.start();

              thread6.start();

       }

 

}

 

2단부터 6단까지의 구구단을 각각의 스레드로 출력하는 내용이네요

하지만 스레드마다 랜덤한 sleep 시간을 두어 순차적으로 실행되는 모양입니다 결과를 보면..

3단은 92만큼 sleep 실행

6단은 74만큼 sleep 실행

4단은 43만큼 sleep 실행

5단은 298만큼 sleep 실행

2단은 51만큼 sleep 실행

4:4 * 1 = 4

4:4 * 2 = 8

4:4 * 3 = 12

4:4 * 4 = 16

4:4 * 5 = 20

4:4 * 6 = 24

4:4 * 7 = 28

4:4 * 8 = 32

4:4 * 9 = 36

2:2 * 1 = 2

2:2 * 2 = 4

2:2 * 3 = 6

2:2 * 4 = 8

2:2 * 5 = 10

2:2 * 6 = 12

2:2 * 7 = 14

2:2 * 8 = 16

2:2 * 9 = 18

6:6 * 1 = 6

6:6 * 2 = 12

6:6 * 3 = 18

6:6 * 4 = 24

6:6 * 5 = 30

6:6 * 6 = 36

6:6 * 7 = 42

6:6 * 8 = 48

6:6 * 9 = 54

3:3 * 1 = 3

3:3 * 2 = 6

3:3 * 3 = 9

3:3 * 4 = 12

3:3 * 5 = 15

3:3 * 6 = 18

3:3 * 7 = 21

3:3 * 8 = 24

3:3 * 9 = 27

5:5 * 1 = 5

5:5 * 2 = 10

5:5 * 3 = 15

5:5 * 4 = 20

5:5 * 5 = 25

5:5 * 6 = 30

5:5 * 7 = 35

5:5 * 8 = 40

5:5 * 9 = 45

정말 sleep 시간이 짧았던것부터 긴것의 순서대로 스레드가 실행되었음을 있습니다

sleep 메소드의 파라미터에는 밀리초(천분의 1) 단위의 long타입 리터럴 혹은 변수를 지정해주시면 됩니다

 

 

다음은 yield 메소드입니다 같은 우선순위에게 양보한다니 대체 무슨 뜻일까요? 소스코드를 보겠습니다

 

package thread;

 

public class YieldTest implements Runnable {

       private int dan;

 

       public YieldTest(int dan) {

              this.dan = dan;

       }

 

       @Override

       public void run() {

              if (dan == 6) {

                     System.out.println("6단은 yield(양보)합니다");

                     Thread.yield();

              }

              for (int i = 1; i <= 9; i++) {

                     System.out.println(dan + ":" + dan + " * " + i + " = " + dan * i);

              }

 

       }

}

 

  

package thread;

 

public class MainClass2 {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              Thread thread2 = new Thread(new YieldTest(2));

        Thread thread3 = new Thread(new YieldTest(3));

        Thread thread4 = new Thread(new YieldTest(4));

        Thread thread5 = new Thread(new YieldTest(5));

        Thread thread6 = new Thread(new YieldTest(6));

        thread2.setPriority(Thread.MAX_PRIORITY);

        thread3.setPriority(Thread.NORM_PRIORITY);

        thread4.setPriority(Thread.MIN_PRIORITY);

        thread5.setPriority(Thread.MIN_PRIORITY);

        thread6.setPriority(Thread.MIN_PRIORITY);

        thread2.start();

        thread3.start();

        thread4.start();

        thread5.start();

        thread6.start();

 

       }

 

}

 

setPriority 메소드는 스레드간의 우선순위를 설정하는 일을 합니다 1~10까지의 값을 넣을 있구요

소스코드에서처럼 Thread 클래스의 static 상수를 사용해도 됩니다

MAX_PRIORITY 10, NORM_PRIORITY 5, MIN_PRIORITY 1 같습니다

숫자가 높을수록 우선순위가 높다는 얘기입니다 이제 실행결과를 보겠습니다

2:2 * 1 = 2

2:2 * 2 = 4

2:2 * 3 = 6

2:2 * 4 = 8

2:2 * 5 = 10

2:2 * 6 = 12

2:2 * 7 = 14

2:2 * 8 = 16

2:2 * 9 = 18

4:4 * 1 = 4

4:4 * 2 = 8

3:3 * 1 = 3

4:4 * 3 = 12

6단은 yield(양보)합니다

5:5 * 1 = 5

5:5 * 2 = 10

5:5 * 3 = 15

5:5 * 4 = 20

5:5 * 5 = 25

5:5 * 6 = 30

5:5 * 7 = 35

5:5 * 8 = 40

5:5 * 9 = 45

6:6 * 1 = 6

4:4 * 4 = 16

3:3 * 2 = 6

3:3 * 3 = 9

3:3 * 4 = 12

3:3 * 5 = 15

3:3 * 6 = 18

3:3 * 7 = 21

3:3 * 8 = 24

3:3 * 9 = 27

4:4 * 5 = 20

4:4 * 6 = 24

4:4 * 7 = 28

4:4 * 8 = 32

4:4 * 9 = 36

6:6 * 2 = 12

6:6 * 3 = 18

6:6 * 4 = 24

6:6 * 5 = 30

6:6 * 6 = 36

6:6 * 7 = 42

6:6 * 8 = 48

6:6 * 9 = 54

6단이 시작되려던 4:4 * 3 = 12 다음부분에서 6단의 스레드는 5단에게 양보를 하고 나중에 시작됐네요. 하지만 결과가 항상 나오는 것은 아닙니다 결국에는 스레드 스케쥴러에 의해서 결정되는 일이기 때문입니다

 

현재 실행중이던 스레드를 Blocking 하고 join 요청한 스레드가 작업을 마치길 기다리는지 확인해보겠습니다.

 

package thread;

 

public class JoinTest implements Runnable {

 

       private int start;

       private int end;

       private int result;

 

       public JoinTest(int start, int end) {

              this.start = start;

              this.end = end;

       }

 

       @Override

       public void run() {

              System.out.println(start + "부터 " + end + "까지 더해봅니다");

              for (int i = start; i <= end; i++) {

                     result += i;

              }

       }

 

       public int getResult() {

              return result;

       }

 

}

 

 

package thread;

 

public class MainClass3 {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              JoinTest joinTest = new JoinTest(1, 100);

              Thread thread = new Thread(joinTest);

              thread.start();

              try {

                     // thread.join();

              } catch (Exception e) {

                     e.getMessage();

              }

              System.out.println(joinTest.getResult());

              System.out.println("main() 종료");

 

       }

 

}

 

 

여기서는 join 메소드를 주석처리 해봤습니다 프로그램의 의도는 JoinTest 넘기는 파라미터(시작값,최대값) 가지고

최소값부터 최대값까지 합산한 결과를 main 메소드의 마지막에 출력해야합니다

thread 모든 작업을 마칠때까지 main 스레드는 대기해줘야합니다 그런데 결과를 보시면..

0

1부터 100까지 더해봅니다

main() 종료

이런~ 아직 thread 1부터 100까지 더하는 연산을 마치지도 못했는데 main 멋대로 결과값을 출력하고 종료되어버렸습니다

 

다시 join 주석을 풀면 결과는 이렇습니다

1부터 100까지 더해봅니다

5050

main() 종료

이제 의도한대로 결과가 나왔습니다 1부터 100까지 더하는 동안 main 메소드의 다음 명령문들은 실행되지 않고 대기했네요

연산이 끝나자마자(thread 종료되자마자) 부리나케 총합을 출력하고는 종료하는군요

 

출처 : http://n6lab.tistory.com/11

 

 

 


Thread Deadlock Example




Deadlock describes a situation where two or more threads are blocked forever, waiting for each other. Deadlock occurs when multiple threads need the same locks but obtain them in different order. A Java multithreaded program may suffer from the deadlock condition because the synchronized keyword causes the executing thread to block while waiting for the lock, or monitor, associated with the specified object. Here is an example:

Example:

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
   
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class ThreadDemo2 extends Thread {
      public void run() {
         synchronized (Lock2) {
            System.out.println("Thread 2: Holding lock 2...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            synchronized (Lock1) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

When you compile and execute above program, you find a deadlock situation and below is the output produced by the program:

Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

Above program will hang forever because neither of the threads in position to proceed and waiting for each other to release the lock, so you can come out of the program by pressing CTRL-C.

Deadlock Solution Example:

Let's change the order of the lock and run the same program to see if still both the threads waits for each other:

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
   
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class ThreadDemo2 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 2: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

So just changing the order of the locks prevent the program in going deadlock situation and completes with the following result:

Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...

Above example has been shown just for making you the concept clear, but its a more complex concept and you should deep dive into it before you develop your applications to deal with deadlock situations.

'Java > Threads' 카테고리의 다른 글

Thread Synchronization  (0) 2013.02.07
Thread & Runnable  (0) 2013.02.07
Posted by Steven J.S Min
,