Skip to content

Commit 2b68472

Browse files
committed
initial commit
0 parents  commit 2b68472

File tree

197 files changed

+8236
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+8236
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/target
2+
/deploy
3+
/.project
4+
/.classpath
5+
/.settings

README.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
Java concurrency 예제
2+
=========
3+
## 예제 출처
4+
- [Effective Java 2nd edition](http://www.yes24.com/24/goods/2416238)
5+
- package: ej2
6+
- 원본 : <http://java.sun.com/docs/books/effective/effective2.zip>
7+
- [Java concurrency in practice](http://www.yes24.com/24/goods/1550580)
8+
- package : net.jcip
9+
- 원본 : <http://jcip.net/listings.html>, <http://jcip.net/jcip-examples-src.jar>
10+
- [Java 언어로 배우는 디자인 패턴 입문 멀티 쓰레드 편](http://www.yes24.com/24/goods/2922297)
11+
- package : jdm
12+
- 원본 : <http://ndisk.youngjin.com/bookcd/pds_view.asp?pcd=9788931436921>
13+
- [유쾌한 자바 퍼즐러](http://www.yes24.com/24/Goods/2600965)
14+
- 원본 : <http://www.javapuzzlers.com/java-puzzlers.zip>
15+
- package : jpz
16+
- [Concurrent Programming Distributed Applications 발표](http://www.infoq.com/presentations/Concurrent-Distributed-Applications-Spring
17+
)
18+
- SpringOne 2GX 2010에서 David Syer와 Mark Fisher가 한 발표
19+
- 원본 : <http://git.springsource.org/s2gx-2010/concurrent-programming-distributed-applications/trees/master/concurrency>
20+
- package : s2gx
21+
- [Think in java 4th Edition](http://www.yes24.com/24/Goods/263372)
22+
- 원본 <http://www.mindviewinc.com/TIJ4/CodeDownload.php>
23+
- 나머지는 직접 작성한 예제
24+
25+
## 장별 예제 정리 링크
26+
27+
### 3. java.lang.Thread 바로 알기
28+
- 쓰지 말아야할 것: Thread.stop
29+
- [PrimeGenerator.java](src/main/java/net/jcip/examples/PrimeGenerator.java) : 협력적으로 Thread를 멈추는 방식
30+
- 잘 알고 쓸 것 : Thread.interrupt
31+
- [SelfInterruption.java](src/main/java/jpz/puzzle84/SelfInterruption.java) : Thread.interrupted()의 혼란성을 보여줌
32+
- [BrokenPrimeProducer.java](src/main/java/net/jcip/examples/BrokenPrimeProducer.java) : BlockingQueue가 blocking되어 있으면 중지되지 않는 쓰레드
33+
- [PrimeProducer.java](src/main/java/net/jcip/examples/PrimeProducer.java) : interrupt로 중지할 수 있는 쓰레드
34+
35+
### 4. 동기화와 가시성
36+
- Sychronized
37+
- [NonreentrantDeadlock.java](src/main/java/net/jcip/examples/NonreentrantDeadlock.java) : synchronized 키워드에 의한 lock은 재진입가능하다는 것을 보여줌
38+
- [SyncDemo.java](src/main/java/study/javacon/SyncDemo.java) : synchronized로 선언된 Block이 동시에 실행되지 못함을 보여줌.
39+
- [PingPong.java](src/main/java/jpz/puzzle76/PingPong.java) : static method의 syncronized 키워드의 동작방식을 보여줌.
40+
- 가시성 확보
41+
- [StopThread.java(Broken)](src/main/java/ej2/item66/broken/StopThread.java) : static 변수이지만 가시성 확보가 안 되어서 한 스레드에서 write한 값이 다른 thread에서 안 보이는 현상을 보여줌.
42+
- [StopThread.java(Fix1)](src/main/java/ej2/item66/fix1/StopThread.java) : 가시성 문제를 synchronized 메소드를 이용해서 동기화 시켜서 해결
43+
- [StopThread.java(Fix2)](src/main/java/ej2/item66/fix2/StopThread.java) : 가시성 문제를 volatile 키워드를 이용해서 해결
44+
- [Worker.java](src/main/java/jpz/puzzle77/Worker.java) : 가시성 확보, 동기화를 모두 했음에도 Thread.join이 호출되면 예상치 못한 동작이 발생함을 보여줌
45+
46+
### 5. Java concurrent API
47+
- Executors
48+
- [TimingThreadPool.java](src/main/java/net/jcip/examples/TimingThreadPool.java) : ThreadPoolExecutor를 확장해서 시간측정 로깅 기능을 추가한 예제
49+
- Callable
50+
- [Preloader.java](src/main/java/net/jcip/examples/Preloader.java) : Callable, FutureTask , Thread 생성, Future.get의 사용예.
51+
- java.util.concurrent.locks패키지
52+
- [ReadWriterMap.java](src/main/java/net/jcip/examples/ReadWriterMap.java) : ReadWriteLock을 활용해서 Map을 동기화한 사례
53+
- CountDownLatch
54+
- [TestHarness.java](src/main/java/net/jcip/examples/TestHarness.java) : CountDownLatch를 이용해서 여러 쓰레드로 작업을 실행하고, 최종 종료시간을 구함
55+
- [ConcurrentTimer.java](src/main/java/ej2/item69/ConcurrentTimer.java) : TestHarness와 유사한 역할이나 스레드 생성 후에 실행되는 구간을 측정하기 위해 단계를 하나 더 두었음.
56+
- Semaphore
57+
- [BoundedHashSet.java](src/main/java/net/jcip/examples/BoundedHashSet.java) : counting semaphore를 활용해 제한된 크기의 Set을 구현함.
58+
- 다양한 동기화 방식
59+
- [CounterDemo.java](src/main/java/s2gx/counter/CounterDemo.java) : Counter의 동작을 확인하는 클래스
60+
- [LockingCounter.java](src/main/java/s2gx/counter/LockingCounter.java) : WriteLock을 이용한 Counter
61+
- [SynchronizedCounter.java](src/main/java/s2gx/counter/SynchronizedCounter.java) : synchronized 키워드를 이용한 클래스
62+
- [AtomicCounter.java](src/main/java/s2gx/counter/AtomicCounter.java) : AtomicInteger를 이용한 클래스
63+
64+
### 6. Thread 안전 클래스
65+
- Iterator
66+
- [IteratorAccessor.java](src/main/java/study/javacon/IteratorAccessor.java) : java.util.ConcurrentModificationException를 드러내주는 예제
67+
- [HiddenIterator.java](src/main/java/net/jcip/examples/HiddenIterator.java) : Iterator를 명시적으로 호출하지 않았는데도 문제가 되는 경우
68+
- [HiddenIteratorAccessor.java](src/main/java/net/jcip/examples/HiddenIteratorAccessor.java) : HiddenIterator의 에러를 드러내주는 클래스
69+
- BlockingQueue
70+
- [PlainProsumer.java](src/main/java/study/javacon/queue/PlainProsumer.java) : wait, notify를 이용한 큐
71+
- [BlockingProsumer.java](src/main/java/study/javacon/queue/BlockingProsumer.java) : BlockingQueue를 이용
72+
73+
- Atomic class
74+
- [SimulatedCAS.java](src/main/java/net/jcip/examples/SimulatedCAS.java) : CAS 동작의 로직을 보여줌.
75+
- [CasCounter.java](src/main/java/net/jcip/examples/CasCounter.java) : CAS 로직을 이용한 Counter
76+
- 설계 원칙
77+
- StackDemo.java : 쓰레드에 한정되어야할 객체를 콜스택 안에서 local변수로 생성하여 메소드 파라미터로 넘김.
78+
- ThreadLocalDemo.java : ThreadLocal을 이용.
79+
### 7. Documentation
80+
- JCIP annotation
81+
- [Memo.java](src/main/java/study/javacon/findbugs/Memo.java) : @Immutable로 선언했을 때 Findbugs를 경고를 보여줌
82+
- [LoginInfo.java](src/main/java/study/javacon/findbugs/LoginInfo.java) : Thread-safe하지 않은 클래스
83+
- [UserService.java](src/main/java/study/javacon/findbugs/UserService.java) : Thread-safe하지 않은 클래스를 멤버변수로 사용하는 코드
84+
85+
### 8. 성능
86+
- 락좁히기
87+
- [AttributeStore.java](src/main/java/net/jcip/examples/AttributeStore.java) : 메소드 단위로 넓게 synchronized 구간을 선엄함.
88+
- [BetterAttriebuteStore.java](src/main/java/net/jcip/examples/BetterAttributeStore.java) : AttributeStore.java에서 꼭 필요한 부분만 synchronized 구간을 잡음
89+
- 락분할
90+
- [ServerStatusBeforeSplit.java](src/main/java/net/jcip/examples/ServerStatusBeforeSplit.java) : 메소드 단위로 넓게 synchronized 구간을 선엄함.
91+
- [ServerStatusAfterSplit.java](src/main/java/net/jcip/examples/ServerStatusAfterSplit.java) : 메소드별로 필요한 객체에만 synchronized를 걸어서 Lock을 분할.
92+
- 락스트라이핑
93+
- [StripedMap.java](src/main/java/net/jcip/examples/StripedMap.java) : 락 스트라이핑을 적용한 Map
94+
- [DefectedStripedMap.java](src/main/java/study/javacon/DefectedStripedMap.java) : StripedMap에서 Hash방식을 바꿈
95+
- [DefectedStripedMapTest.java](src/main/java/study/javacon/DefectedStripedMapTest.java) : DefectedStripedMap의 오류를 드러내는 테스트
96+
- 바쁜 대기 없애기
97+
- [SlowCountDownLatch.java](src/main/java/ej2/item72/SlowCountDownLatch.java) : CountDownLatch를 무식하게 구현.
98+
- [BaseBoundBuffer.java](src/main/java/net/jcip/examples/BaseBoundedBuffer.java) : 크기가 한정된 Buffer의 기본 구현.
99+
- [GrumpyBoundBuffer.java](src/main/java/net/jcip/examples/GrumpyBoundBuffer.java) : 바쁜 대기
100+
- [SleepyBoundBuffer.java](src/main/java/net/jcip/examples/SleepyBoundBuffer.java) : Sleep을 이용해서 바쁜 대기를 약간 없앰
101+
- [BoundedBuffer.java](src/main/java/net/jcip/examples/BoundedBuffer.java) : wait, notify를 이용
102+
- [ConditionBoundBuffer.java](src/main/java/net/jcip/examples/ConditionBoundBuffer.java) : Lock클래스를 이용
103+
- 늦은 초기화
104+
- [Initialization.java](src/main/java/ej2/item71/Initialization.java) : lazy initialization의 여러 방식을 보여줌
105+
- [MySystem.java(Single)](src/main/java/jdm/appendixa/single/MySystem.java) : 초기화 메서드 전체에 동기화가 걸림.
106+
- [MySystem.java(Double Checked)](src/main/java/jdm/appendixa/doublechecked/MySystem.java) : doublechecked lock을 적용
107+
- [MySystem.java(Holder)](src/main/java/jdm/appendixa/holder/MySystem.java) : Holder패턴을 적용할려는 예정으로 있는 클래스
108+
- [ColorPoint.java](src/main/java/jpz/puzzle51/ColorPoint.java) : final필드에 값이 할당되기 전에도 읽는 것이 가능하고, 늦은 초기화가 필요한 경우를 보여줌.

pom.xml

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>net.benelog</groupId>
6+
<artifactId>java-concurrency</artifactId>
7+
<name>java-concurrency</name>
8+
<packaging>jar</packaging>
9+
<version>1.0.0-BUILD-SNAPSHOT</version>
10+
<properties>
11+
<java-version>1.6</java-version>
12+
<org.slf4j-version>1.5.10</org.slf4j-version>
13+
</properties>
14+
<dependencies>
15+
<dependency>
16+
<groupId>javax.servlet</groupId>
17+
<artifactId>javax.servlet-api</artifactId>
18+
<version>3.0.1</version>
19+
<scope>provided</scope>
20+
</dependency>
21+
<dependency>
22+
<groupId>net.jcip</groupId>
23+
<artifactId>jcip-annotations</artifactId>
24+
<version>1.0</version>
25+
</dependency>
26+
<!-- Test -->
27+
<dependency>
28+
<groupId>junit</groupId>
29+
<artifactId>junit</artifactId>
30+
<version>4.8.1</version>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
<build>
35+
<finalName>${artifactId}</finalName>
36+
<plugins>
37+
<plugin>
38+
<groupId>org.apache.maven.plugins</groupId>
39+
<artifactId>maven-compiler-plugin</artifactId>
40+
<configuration>
41+
<source>${java-version}</source>
42+
<target>${java-version}</target>
43+
</configuration>
44+
</plugin>
45+
<plugin>
46+
<groupId>org.apache.maven.plugins</groupId>
47+
<artifactId>maven-dependency-plugin</artifactId>
48+
<executions>
49+
<execution>
50+
<id>install</id>
51+
<phase>install</phase>
52+
<goals>
53+
<goal>sources</goal>
54+
</goals>
55+
</execution>
56+
</executions>
57+
</plugin>
58+
<plugin>
59+
<groupId>org.apache.maven.plugins</groupId>
60+
<artifactId>maven-surefire-plugin</artifactId>
61+
<configuration>
62+
<junitArtifactName>junit:junit</junitArtifactName>
63+
</configuration>
64+
</plugin>
65+
</plugins>
66+
</build>
67+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* @(#)StopThread.java $version 2011. 11. 16.
3+
*
4+
* Copyright 2007 NHN Corp. All rights Reserved.
5+
* NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6+
*/
7+
8+
package ej2.item66.broken;
9+
10+
import java.util.concurrent.TimeUnit;
11+
12+
/**
13+
* @author benelog
14+
*/
15+
public class StopThread {
16+
private static Boolean stopRequested = Boolean.FALSE;
17+
18+
public static void main(String[] args)
19+
throws InterruptedException {
20+
Thread backgroundThread = new Thread(new Runnable() {
21+
public void run() {
22+
int i = 0;
23+
while (stopRequested.equals(Boolean.FALSE))
24+
i++;
25+
}
26+
27+
});
28+
backgroundThread.start();
29+
30+
TimeUnit.SECONDS.sleep(1);
31+
stopRequested = Boolean.TRUE;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package ej2.item66.fix1;
2+
3+
4+
// Properly synchronized cooperative thread termination - Page 261
5+
6+
import java.util.concurrent.*;
7+
8+
public class StopThread {
9+
private static boolean stopRequested;
10+
private static synchronized void requestStop() {
11+
stopRequested = true;
12+
}
13+
private static synchronized boolean stopRequested() {
14+
return stopRequested;
15+
}
16+
17+
public static void main(String[] args)
18+
throws InterruptedException {
19+
Thread backgroundThread = new Thread(new Runnable() {
20+
public void run() {
21+
int i = 0;
22+
while (!stopRequested())
23+
i++;
24+
}
25+
});
26+
backgroundThread.start();
27+
28+
TimeUnit.SECONDS.sleep(1);
29+
requestStop();
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ej2.item66.fix2;
2+
3+
4+
// Cooperative thread termination with a volatile field
5+
6+
import java.util.concurrent.*;
7+
8+
public class StopThread {
9+
private static volatile boolean stopRequested;
10+
11+
public static void main(String[] args)
12+
throws InterruptedException {
13+
Thread backgroundThread = new Thread(new Runnable() {
14+
public void run() {
15+
int i = 0;
16+
while (!stopRequested)
17+
i++;
18+
}
19+
});
20+
backgroundThread.start();
21+
22+
TimeUnit.SECONDS.sleep(1);
23+
stopRequested = true;
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package ej2.item69;
2+
3+
import java.util.concurrent.*;
4+
5+
public class ConcurrentTimer {
6+
private ConcurrentTimer() { } // Noninstantiable
7+
8+
public static long time(Executor executor, int concurrency,
9+
final Runnable action) throws InterruptedException {
10+
final CountDownLatch ready = new CountDownLatch(concurrency);
11+
final CountDownLatch start = new CountDownLatch(1);
12+
final CountDownLatch done = new CountDownLatch(concurrency);
13+
14+
for (int i = 0; i < concurrency; i++) {
15+
executor.execute(new Runnable() {
16+
public void run() {
17+
ready.countDown(); // Tell timer we're ready
18+
try {
19+
start.await(); // Wait till peers are ready
20+
action.run();
21+
} catch (InterruptedException e) {
22+
Thread.currentThread().interrupt();
23+
} finally {
24+
done.countDown(); // Tell timer we're done
25+
}
26+
}
27+
});
28+
}
29+
30+
ready.await(); // Wait for all workers to be ready
31+
long startNanos = System.nanoTime();
32+
start.countDown(); // And they're off!
33+
done.await(); // Wait for all workers to finish
34+
return System.nanoTime() - startNanos;
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package ej2.item71;
2+
3+
// Initialization styles - Pages 282-284
4+
public class Initialization {
5+
6+
// Normal initialization of an instance field - Page 282
7+
private final FieldType field1 = computeFieldValue();
8+
9+
// Lazy initialization of instance field - synchronized accessor - Page 282
10+
private FieldType field2;
11+
synchronized FieldType getField2() {
12+
if (field2 == null)
13+
field2 = computeFieldValue();
14+
return field2;
15+
}
16+
17+
// Lazy initialization holder class idiom for static fields - Page 283
18+
private static class FieldHolder {
19+
static final FieldType field = computeFieldValue();
20+
}
21+
static FieldType getField3() { return FieldHolder.field; }
22+
23+
24+
// Double-check idiom for lazy initialization of instance fields - Page 283
25+
private volatile FieldType field4;
26+
FieldType getField4() {
27+
FieldType result = field4;
28+
if (result == null) { // First check (no locking)
29+
synchronized(this) {
30+
result = field4;
31+
if (result == null) // Second check (with locking)
32+
field4 = result = computeFieldValue();
33+
}
34+
}
35+
return result;
36+
}
37+
38+
// Single-check idiom - can cause repeated initialization! - Page 284
39+
private volatile FieldType field5;
40+
private FieldType getField5() {
41+
FieldType result = field5;
42+
if (result == null)
43+
field5 = result = computeFieldValue();
44+
return result;
45+
}
46+
47+
private static FieldType computeFieldValue() {
48+
return new FieldType();
49+
}
50+
}
51+
52+
class FieldType { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ej2.item72;
2+
3+
// Awful CountDownLatch implementation - busy-waits incessantly!
4+
public class SlowCountDownLatch {
5+
private int count;
6+
public SlowCountDownLatch(int count) {
7+
if (count < 0)
8+
throw new IllegalArgumentException(count + " < 0");
9+
this.count = count;
10+
}
11+
12+
public void await() {
13+
while (true) {
14+
synchronized(this) {
15+
if (count == 0) return;
16+
}
17+
}
18+
}
19+
public synchronized void countDown() {
20+
if (count != 0)
21+
count--;
22+
}
23+
}

0 commit comments

Comments
 (0)