Thread 설계
- Step 1. Single Thread Model
: AutoCloseable Interface1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.concurrent.Executor;
import
java.util.concurrent.Executors;
// C99, C11(thread) - Android M
// C++11/14
// Java 8, 9
public
class
Example3 {
/*
private static void handleRequest(Socket connection) {
OutputStream os = null;
try {
os = connection.getOutputStream();
os.write("Hello World".getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null)
try {
os.close();
} catch (IOException e) {
}
}
}
*/
// Try with Resource : Java 7 - (C# using block)
// 1. Connection, Socket, Stream 비 메모리 자원을 해지하는
// 명시적인 종료 메소드를 호출해야 하는 것은 코드를 어지럽힌다.
// 2. try 블록에 존재하는 자원을 자동으로 회수해준다.
// 3. AutoCloseable Interface
private
static
void
handleRequest(Socket connection) {
try
(OutputStream os = connection.getOutputStream();
InputStream is = connection.getInputStream()) {
os.write(
"Hello World"
.getBytes());
os.flush();
}
catch
(IOException e) {
}
}
// Step 1. Single Thread Model
// 1) 한번에 하나의 요청을 처리하는 것이 가능하다.
// 2) 단일 스레드에서 IO 작업 등으로 대기하는 경우, 하드웨어 자원을
// 효과적으로 사용할 수 없다.
public
static
void
main(String[] args)
throws
IOException {
ServerSocket socket =
new
ServerSocket(
8080
);
while
(
true
) {
Socket connection = socket.accept();
handleRequest(connection);
}
}
- Step 2. Thread per Connection Model1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.concurrent.Executor;
import
java.util.concurrent.Executors;
// C99, C11(thread) - Android M
// C++11/14
// Java 8, 9
public
class
Example3 {
// Try with Resource : Java 7 - (C# using block)
// 1. Connection, Socket, Stream 비 메모리 자원을 해지하는
// 명시적인 종료 메소드를 호출해야 하는 것은 코드를 어지럽힌다.
// 2. try 블록에 존재하는 자원을 자동으로 회수해준다.
// 3. AutoCloseable Interface
private
static
void
handleRequest(Socket connection) {
try
(OutputStream os = connection.getOutputStream();
InputStream is = connection.getInputStream()) {
os.write(
"Hello World"
.getBytes());
os.flush();
}
catch
(IOException e) {
}
}
// Step 2. Thread per Connection Model
// 순차적인 실행 방법보다 훨씬 더 많은 작업을 수행하는 것이 가능하다.
// 문제점
// 1. 엄청나게 많은 스레드가 생성된다.
// 2. Thread 를 만들고 제거하는 작업에도 자원이 소모된다.
// : 클라이언트의 요청이 작은 단위로 일어나는 경우에는 더욱더 문제가 심하다.
// 3. 자원 낭비가 심하다.
// 1) 실행 중인 스레드는 메모리를 많이 소모한다.
// Java의 스택은 두 개이다.(Java, Native)
// 2) 프로세서의 개수 보다 많은 스레드가 생성되면 대부분의 스레드는
// 대기 상태에 있다.
// 4. 컨텍스트 스위칭의 비용이 크다.
// 5. OS 에서 생성할 수 있는 스레드의 개수는 제한되어 있다.
public
static
void
main(String[] args)
throws
IOException {
ServerSocket socket =
new
ServerSocket(
8080
);
while
(
true
) {
final
Socket connection = socket.accept();
Runnable task =
new
Runnable() {
@Override
public
void
run() {
handleRequest(connection);
}
};
new
Thread(task).start();
}
}
- Step 3. Pool-based Model1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.concurrent.Executor;
import
java.util.concurrent.Executors;
// C99, C11(thread) - Android M
// C++11/14
// Java 8, 9
public
class
Example3 {
// Try with Resource : Java 7 - (C# using block)
// 1. Connection, Socket, Stream 비 메모리 자원을 해지하는
// 명시적인 종료 메소드를 호출해야 하는 것은 코드를 어지럽힌다.
// 2. try 블록에 존재하는 자원을 자동으로 회수해준다.
// 3. AutoCloseable Interface
private
static
void
handleRequest(Socket connection) {
try
(OutputStream os = connection.getOutputStream();
InputStream is = connection.getInputStream()) {
os.write(
"Hello World"
.getBytes());
os.flush();
}
catch
(IOException e) {
}
}
// Step 3. Pool-based Model
// 순차적으로 문제를 해결하는 방법은 응답 속도와 전체적인 성능이 떨어지는
// 문제점이 있고 작업별로 스레드를 만들어 내는 방법은 자원 관리 측면에서
// 문제점이 있다
// 해결책)
// 1) 스레드의 생성을 제한해야 한다 -> Thread pool
// 2) 생산자 & 소비자 모델
public
static
final
int
NTHREADS =
100
;
public
static
final
Executor exec = Executors.newFixedThreadPool(NTHREADS);
// 1) newFixedThreadPool
// 작업이 등록되면 제한된 개수까지 스레드를 생성해서 해당 작업을 처리한다.
// 생성 이후에 더 이상 생성하지 않고 스레드 수를 유지한다.
// 2) newCachedThreadPool
// 스레드 수가 처리할 작업보다 많아서 쉬는 스레드가 발생하면,
// 스레드를 종료한다.
// 3) newSingleThreadPool
// 단일 스레드로 처리한다. 등록된 작업은 다양한 정책에 의해서 수행될 수 있다.
// (LIFO, FIFO, 우선순위)
public
static
void
main(String[] args)
throws
IOException {
ServerSocket socket =
new
ServerSocket(
8080
);
while
(
true
) {
Socket connection = socket.accept();
Runnable task =
new
Runnable() {
@Override
public
void
run() {
handleRequest(connection);
}
};
exec.execute(task);
}
}
}
- 스레드의 중단 및 종료 처리
- 1_동기화1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
// 스레드의 중단 및 종료 처리
// 1. 스레드를 만들고 시작하는 것은 쉬운 일이다.
// 2. 스레드를 안전하고 빠르게 멈추게 하는 것은 어렵다.
// 3. 자바의 스레드를 멈추는 기능이 폐기되었다.
// Thread.stop() / Thread.suspend()
// 4. 스레드를 강제로 종료하면 공유되어 있는 여러 가지 상태가
// 망가질 수 있다.
// 5. 스레드를 멈춰달라는 요청이 오면 진행 중이던 모든 작업을 정리한 후
// 스스로 종료하도록 만들어야 한다.
import
java.util.concurrent.TimeUnit;
/*public class Example4 {
private static boolean stopRequested = false;
// 문제점 : main 스레드가 변경한 stopRequested 의 새로운 값을 background
// thread 가 관측할 수 없다.
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
@Override
public void run() {
long i = 0;
while (!stopRequested) {
i++;
//System.out.println("value - " + i);
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(3);
stopRequested = true;
}
}
*/
// 문제점 : main 스레드가 변경한 stopRequested 의 새로운 값을 background
// thread 가 관측할 수 없다.
// 해결책 1. 동기화(synchronization)
// 1) 상호 배제 : 다른 스레드가 변경 중인 객체의 상태를 관측할 수 없도록 해준다. - 락
// 2) 동기화는 동기화 메소드 또는 동기화 블록에 의해 진입한 스레드가 동일한 락의 보호 아래
// 이루어진 모든 변경을 관측할 수 있다.
// 문제점 : 순환문의 각 단계마다 동기화를 실행하는 비용이 크다.
public
class
Example4 {
private
static
synchronized
void
stop() { stopRequested =
true
; }
private
static
synchronized
boolean
isStopRequested() {
return
stopRequested;
}
private
static
boolean
stopRequested =
false
;
public
static
void
main(String[] args)
throws
InterruptedException {
Thread backgroundThread =
new
Thread(
new
Runnable() {
@Override
public
void
run() {
long
i =
0
;
while
(!isStopRequested()) {
i++;
System.out.println(
"value - "
+ i);
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(
3
);
stop();
stopRequested =
true
;
}
}
- 2_cv 제한자 (const-volatile)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package kr.co.ioacademy; //iocademy 윤찬식 강사님 // 스레드의 중단 및 종료 처리 // 1. 스레드를 만들고 시작하는 것은 쉬운 일이다. // 2. 스레드를 안전하고 빠르게 멈추게 하는 것은 어렵다. // 3. 자바의 스레드를 멈추는 기능이 폐기되었다. // Thread.stop() / Thread.suspend() // 4. 스레드를 강제로 종료하면 공유되어 있는 여러 가지 상태가 // 망가질 수 있다. // 5. 스레드를 멈춰달라는 요청이 오면 진행 중이던 모든 작업을 정리한 후 // 스스로 종료하도록 만들어야 한다. import java.util.concurrent.TimeUnit; // cv 제한자(const-volatile) : C, C++, C# - Debug / [Release] // 해결책 2. volatile // 정의 : 컴파일러가 최적화를 하지 말라는 지시어 (내부에 cache하여 사용하지 않도록 막음.) // 멀티 스레드 상에서 공유되는 변수, 하드웨어와 연결된 변수 사용시 // 되도록 volatile 붙이자. // 효과 : 어떤 스레드건 가장 최근에 기록된 값을 읽을 수 있다. public class Example4 { private static volatile boolean stopRequested = false ; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread( new Runnable() { @Override public void run() { long i = 0 ; while (!stopRequested) { i++; System.out.println( "value - " + i); } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep( 3 ); stopRequested = true ; } } |
'Programing > Java' 카테고리의 다른 글
Effective Java - Reflection (0) | 2016.03.08 |
---|---|
Effective Java - 스레드(2) (0) | 2016.03.07 |
Effective Java - 불변 객체 (0) | 2016.03.07 |
Effective Java - 객체 비교, 복제 (0) | 2016.03.04 |
Effective Java - 객체 소멸 (0) | 2016.03.04 |