Thread
프로세스
: 프로세스는 프로그램에 대한 각각의 인스턴스를 의미하므로, 같은 프로그램을 여러 개 띄웠다고 해서 하나의 프로세스를 공유하는 것은 아니다.
: 프로세스는 운영체제로부터 주소공간, 파일, 메모리 등을 할당받는다.
: 간단히 말하면 실행중인 프로그램
: 프로그램을 수행하는데 필요한 데이터, 메모리, 자원, 쓰레드로 구성되어 있다.
쓰레드
: 프로세스의 자원으로 실제 작업을 실행하는 것이 쓰레드이다.
: 한 프로세스 내에서 동작되는 여러 실행의 흐름으로, 프로세스 내의 주소 공간이나 자원들을 대부분 공유하면서 실행된다.
프로세스와 쓰레드
> 프로세스는 자신만의 고유 공간과 자원을 할당 받아 사용하는데 비해 스레드는 다른 스레드와 공간과 자원을 공유하여 사용한다.
Thread 사용의 장점
: 스레드는 프로세스내에서 각각의 스택 공간을 제외한 나머지 공간과 시스템 자원을 공유한다.
: 그러므로 프로세스를 이용하여 동시에 처리하던 일을 스레드로 구현할 경우 메모리 공간은 물론 시스템 자원 소모도 현격히 줄어든다.
: 스레드 간의 통신이 필요할 경우 별도의 자원을 이용하는 것이 아니라 전역 변수의 공간을 이용하여 데이터를 주고 받을 수 있다.
- 시스템의 처리량이 향상된다.
- 시스템의 자원 소모가 줄어든다.
- 프로그램의 응답 시간이 단축된다.
- 프로세스 간 통신 방법에 비해 스레드 간의 통신 방법이 훨씬 간단하다.
( 스레드 간의 통신 시 데이터를 주고받는 방법은 메모리 공간을 공유하므로 데이터 세그먼트, 즉 전역 변수를 이용하여 구현한다. )
(공유하는 전역 변수를 여러 스레드가 함께 사용하기 위해서는 충돌 문제가 발생할 수 있는데 이런 문제가 발생하지 않도록 동기화 문제를 해결해야 한다.)
Thread 사용의 단점
: 여러 개의 스레드를 이용하는 프로그램을 작성하는 경우 주의 깊게 설계해야 한다.
: 미묘한 시간 차나 잘못된 변수를 공유함으로써 오류가 발생할 수 있다.
자바에서의 Thread
1. 쓰레드 클래스 상속하기 (다른 클래스를 상속받을 수 없다.)
public class ThreadEx extends Thread {
@Override
public void run() { // Thread 코드
}
public static void main(String[] args) {
new ThreadEx().start(); // 쓰레드 시작 .start();
}
}
2. Runnable 인터페이스 구현하기 (재사용성이 높으며, 일관성 유지가능)
public class ThreadEx implements Runnable {
@Override
public void run() { // Thread 코드
}
public static void main(String[] args) {
ThreadEx tEx = new ThreadEx();
Thread t = new Thread(tEx); // 쓰레드 구현
t.start();
}
}
3. 쓰레드의 특징
- start() vs run()
- start()
: 새로운 스레드가 작업을 실행하는데 필요한 호출스택을 생성한 후 run()을 호출 해 새로 생성한 호출스택 첫번째로 run()을 저장한다.
- run()
: 스레드를 실행시키는게 아니라 클래스에 속한 메서드 하나를 호출하는 것
※ 모든 쓰레드는 독립적인 작업 수행을 위해 자신만의 호출 스택을 필요로 하기 때문에
새로운 쓰레드를 생성하고 실행시킬 때마다 새로운 호출스택이 생성되고 쓰레드가 종료되면 호출 스택은 소멸된다.
run() 메소드 호출 시 Main() 위에 Run() 메소드를 하나 호출하는 것 | start()할 때 독립적인 작업 수행을 위해 쓰레드마다 각자의 콜 스택을 생성 run() 메소드를 실행한다. ※ 4개의 호출스택(Thread)가 번갈아 가며 실행하는 멀티쓰레드(다중처리처럼 보이는 것) |
4. Thread의 동기화(synchronized)
: 싱글스레드의 경우 프로세스 내 단 하나의 스레드만 작업하기 때문에 자원을 이용하는 데에 문제가 없지만 멀티 스레드일 경우 같은 자원을 공유할 때 문제가 생길 수 있다.
: 그렇기 때문에 현재 작업 시 lock을 걸어 다른 스레드가 접근하지 못하게 하는 작업이 필요하다. 이 작업을 '동기화(synchronized)'라고 한다.
- 하나의 객체에 다수의 Thread가 접근 시
Synchronized(객체 참조변수) { }
- 하나의 메서드 내에서 객체 참조를 하는 경우
public Synchronized void 메소드명( ) { }
MultiThread Example Code
public class Multithread {
SharedArea area; // 공유 객체 선언
public Multithread() {
area = new SharedArea(); // 공유 객체 생성
area.account1 = new Account("111-111-1111", "이몽룡", 20000000);
area.account2 = new Account("222-222-2222", "성춘향", 10000000);
TransferThread thread1 = new TransferThread(area); // 입/출금 Thread 객체
thread1.start();
PrintThread thread2 = new PrintThread(area); // 결과 출력 Thread 객체
thread2.start();
}
public static void main(String[] args) {
new Multithread();
}
}
/**
*
* @author SeokRae
* @Description 출력 Thread
*/
class PrintThread extends Thread {
SharedArea sharedArea;
public PrintThread(SharedArea area) {
sharedArea = area;
}
@Override
public void run() {
for (int cnt = 0; cnt < 12; cnt++) {
int sum = sharedArea.getTotal();
System.out.println("계좌 잔액 합계 : " + sum);
try {
Thread.sleep(1); // 두 Thread의 실행 시간을 맞추기 위해 1/1000 초간 시간을 지연시킨다.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
*
* @author SeokRae
* @description 입/출금
*/
class TransferThread extends Thread {
SharedArea sharedArea; // 공유 객체 선언
public TransferThread(SharedArea area) {
this.sharedArea = area;
}
@Override
public void run() {
for (int cnt = 0; cnt < 12; cnt++) {
sharedArea.transfer(100); // 계좌 이체 메소드 호출
try {
Thread.sleep(1); // 두 Thread의 실행 시간을 맞추기 위해 1/1000 초간 시간을 지연시킨다.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
*
* @author SeokRae
* @description 계좌정보
*/
class Account {
String accountNo; // 계좌번호
String ownerName; // 예금주 이름
int balance; // 잔액
// shift + art + s > o
// 필드 값을 모두 사용하는 생성자
public Account(String accountNo, String ownerName, int balance) {
this.accountNo = accountNo;
this.ownerName = ownerName;
this.balance = balance;
}
void deposit(int amount) { // 입금
balance += amount; // 예금액을 잔액에 추가
}
int withdraw(int amount) { // 출금
if (balance < amount) { // 잔액값보다 출금액이 클 경우
return 0;
}
balance -= amount; // 잔액에서 출금액을 뺀다.
return amount;
}
}
/**
*
* @author SeokRae
* @description 공유 객체
* @function 계좌 입/출력, 합계
*/
class SharedArea {
Account account1;
Account account2;
synchronized void transfer(int amount) {
// synchronized(this){
account1.withdraw(amount * 10000);
System.out.print("이몽룡 계좌 : " + amount + "만원 인출 ,");
account2.deposit(amount * 10000);
System.out.println("성춘향 계좌 : " + amount + "만원 입금");
// }
}
synchronized int getTotal() { // 잔액의 합계를 구한다.
return account1.balance + account2.balance;
}
}
'학업' 카테고리의 다른 글
[네트워크 프로그래밍] - Collection Framework (0) | 2017.05.07 |
---|---|
[네트워크 프로그래밍] - Generic (0) | 2017.05.07 |
[네트워크 프로그래밍(JAVA)] I/O (0) | 2017.04.29 |
c언어 fgets, strcpy, strtok (2) | 2017.04.01 |
[네트워크 프로그래밍] 응용계층 프로토콜 종류 (0) | 2017.03.07 |