Thread 18
package kr.or.ddit.basic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
/*
Vector , Hashtable 등의 예전부터 존재하던 Collection 객체들은 내부에 동기화 처리가 되어 있다.
그런데, 최근에 새로 구성된 Collection 들은 동기화 처리가 되어 있지 않다.
그래서, 동기화가 필요한 프로그램에서 이런 Collection 들을 사용하려면 동기화 처리를 해 준 후에 사용해야한다.
//동기화 처리 : multi-thread로 동시접근되는것을 막는다! 싱크로나이즈
*/
public class ThreadTest18 {
public static void main(String[] args) {
Vector<Integer> vec = new Vector <>();
//동기화 처리가 되지 않은 List ( 새로생긴 애들은 동기화처리가 자동으로되는게 아니라 필요할때 개발자들이 한다. )
List<Integer> list1 = new ArrayList<>();
//쓰레드가 침범할 수 있어. 기본적으로 IndexOutOfBoundsException 예외가 생긴다.
//-> 기본적으로 Array 는 10 개의 길이를 만든다. 만약 add 를 통해서 10개 보다 더 많이 넣을때
//새로운 배열이 만들어지는데, 그때 다시 다른 쓰레드가 침범을 할 수 있다.
//동기화 처리를 한 경우
List<Integer> list2 = Collections.synchronizedList(new ArrayList<>());
// Synchronized 동기화 처리를 하기 위해서 자원을 사용하게 된다. -> 새로생기는 Collections 에서는
// 동기화처리를 필요할 떄만 하도록 하기로 하자고 함. 자원을 아끼게 됨
//익명 구현체로 스레드 구현
Runnable r = new Runnable() {
@Override
public void run() {
for(int i = 0 ; i < 10000 ; i++) {
vec.add(i);
list2.add(i);
}
}
};
Thread[] ths = new Thread[] {
new Thread(r) , new Thread(r),new Thread(r) , new Thread(r),new Thread(r)
};
for(Thread th : ths) {
th.start();
}
for(Thread th : ths) {
try {
th.join();
} catch (InterruptedException e) {
}
}
System.out.println("vec 의 개수 " + vec.size());
//System.out.println("list1 의 개수 " + list1.size());
System.out.println("list2 의 개수 " + list2.size());
}
}
----------------------------------------------------------------------------------------------
ThreadTest19
package kr.or.ddit.basic;
/*
wait () , notify() 메서드를 이용한 예제
(두 쓰레드가 번갈아 한번씩 실행되는 예제 )
*/
public class ThreadTest19 {
public static void main(String[] args) {
WorkObject workObj = new WorkObject();
ThreadA tha = new ThreadA(workObj);
ThreadB thb = new ThreadB(workObj);
thb.start();
tha.start();
}
}
//공통으로 사용할 객체
class WorkObject {
public synchronized void testMethod1() {
System.out.println("testMethod1() 메서드 실행중...");
notify() ; //wait() 를 먼저 실행하면 wait() 가 두개 먼저 실행되면, 깨워줄 애가 없어..
try {
wait(); //아래도 wait() 가 있기 떄문에 마지막에 누가 끝나든 wait() 에 있다. 그래서 마지막단계를 만들어줘야함
} catch (InterruptedException e) {
}
}
public synchronized void testMethod2() {
System.out.println("testMethod2() 메서드 실행중...");
notify() ;
try {
wait();
} catch (InterruptedException e) {
}
}
}
//WorkObject 의 testMethod1() 메서드만 실행하는 쓰레드
class ThreadA extends Thread {
private WorkObject workObj ;
public ThreadA(WorkObject workObj) {
super();
this.workObj = workObj ;
}
@Override
public void run() {
for(int i=0 ; i < 10 ; i++ ) {
workObj.testMethod1();
}
// 마지막에 wait상태를 깨워준다.
synchronized (workObj) {
workObj.notify();
}
}
}
class ThreadB extends Thread {
private WorkObject workObj ;
public ThreadB(WorkObject workObj) {
super();
this.workObj = workObj ;
}
@Override
public void run() {
for(int i=0 ; i < 10 ; i++ ) {
workObj.testMethod2();
}
//마지막에 wait 상태를 깨워준다.
synchronized (workObj) {
workObj.notify();
}
}
}
----------------------------------------------------------------------------------------------
ThreadTest20
package kr.or.ddit.basic;
public class ThreadTest20 {
public static void main(String[] args) {
DataBox box = new DataBox();
ProducerThread th1 = new ProducerThread(box);
ConsumerThread th2 = new ConsumerThread(box);
th2.start();
th1.start();
}
}
class DataBox {
private String data;
//데이터를 가져가는 메서드
// 데이터를 공통으로 관리하는 클래스
// 처리과정 ==> data 변수의 값이 null이면 data 변수에 문자열이 채워질 때까지 기다리고
// data 변수의 값이 있으면 해당 문자열을 반환한다.
// data 변수의 값을 반환한 후에는 data변수의 값을 null 로 만든다.
public synchronized String getData() {
if (data == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
String returnData = data;
System.out.println("쓰레드가 읽은 데이터 : " + returnData);
data = null ;
notify ();
return returnData ;
}
// 데이터를 넣어주는 메서드
// 처리과정 == data 변수의 값이 있으면 data변수의 값이 null 이 될 때까지 기다린다.
// data 변수의 값이 null 이 되면 data 변수에 새로운 값으로 저장한다.
public synchronized void setData(String data) {
if (this.data != null) {
try {
wait();
} catch (InterruptedException e) {
}
} //if 문 끝
this.data = data;
System.out.println("Thread 에서 새로 저장한 데이터 : " + data);
notify(); //항상 저장을 먼저하고 (이부분 ) 읽기는 나중에 ( getData() )
}
}
//데이터를 넣어주는 쓰레드
class ProducerThread extends Thread {
private DataBox box;
public ProducerThread(DataBox box) {
super();
this.box = box;
}
@Override
public void run() {
for(int i = 1 ; i <= 5 ; i++) {
box.setData("공급 데이터 " + i);
}
}
}
//데이터를 꺼내서 사용하는 쓰레드
class ConsumerThread extends Thread {
private DataBox box;
public ConsumerThread(DataBox box) {
super();
this.box = box;
}
@Override
public void run() {
for(int i = 1 ; i <= 5 ; i++) {
String data = box.getData(); //이 data 는 역할은 현재 여기서는 없지만 뒤에 문장에
//다른 실행문들이 더 나오면 밑에서 더 쓰일 수 있다.
}
}
}
댓글
댓글 쓰기