Java - Thread(싱글, 다중(멀티), 스위칭), 동기화

|

 

package Week02.day0719;

import java.sql.Date;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;



class Car{
	private String model; // 모델명
	private int effciency; // 연비 (cc)
	private int distance; // 뛴거리 (km)
	private HashMap fixHis = new HashMap(); // 수리이력
	private String nowOwner;
	private HashSet accidentHis = new HashSet(); // 사고이력
	
	Car(String model, int effciency, int distance, String nowOwner){
		this.model = model;
		this.effciency = effciency;
		this.distance = distance;
		this.nowOwner = nowOwner;
	}
	
	public void addAccidentHis() throws Exception { //		사고이력을 추가한다. HashMap
//        - info: location(장소), date(20190102), time(12:50)이 / 를 구분자로 add
		//구분자 쓰는법 : String data[] = info.split("/");
//            ex. format : " 로타리사거리/20190501/14:00 "
//        - 조건1:  같은 사고이력을 추가할 수 없다
//        - 조건2:  잘못된 날짜와 시간이 추가되면 안된다(ex. 55시. 55월...)
		
		AccidentHis in = new AccidentHis("로타리사거리", "20190228", "12:00");
		
		//같은 사고이력 체크 , hashset은 중복체크 스스로 하므로 필요가 없다.
		if(accidentHis.contains(in)) {
			throw new Exception("같은 사고이력을 추가하실 수 없습니다.");
		}
		
		//잘못된 날짜와 시간 추가 방지 체크
		if(Util.validationDate(in.getDate() + " " + in.getTime()))
			accidentHis.add(in);
		else
			throw new Exception("잘못된 날짜이거나 잘못된 시간 형식입니다.");
	}
	
	public void printAccidnetHis() throws ParseException{ // 사고이력을 출력한다. HashMap
//		형식: ‘{0} - {1} ? {2}’, {0}: 장소, {1}: 날자, {2}: 시간
//                날자는 xxxx.xx.xx Format으로 출력한다
		
		SimpleDateFormat original_format = new SimpleDateFormat("yyyyMMdd");
		SimpleDateFormat new_format = new SimpleDateFormat("yyyy.MM.dd");
		Iterator it = accidentHis.iterator();
		while(it.hasNext()) { // hasnext를 쓰면 아래 에선 쓰지 못하므로 변수를 써서 한다.
			AccidentHis e = (AccidentHis) it.next();
			java.util.Date original_date = original_format.parse(e.getDate());
			String new_date = new_format.format(original_date);
			String msg = "{0} - {1} ? {2}";
			Object[] arguments = {((AccidentHis)e).getLocation(), new_date, ((AccidentHis)e).getTime()};
			String result = MessageFormat.format(msg, arguments);
			System.out.println(result);
		}
		
	}
	
	//SubString으로 활용하는 방법도 있다.
//	public boolean DateCheck(int month, int date, int hour, int min) {
//		if(month>0 && month<=12)
//			if(date>0 && date<=31)
//				if(hour>=0 && hour <24)
//					if(min>=0 && min<60)
//						return true;
//		return false;
//	}
//	public void addAccidentHis(String info) {
//		String[]ac = info.split("/");
//		int month = (Integer.parseInt(ac[1].substring(4, 6)));
//		int date = (Integer.parseInt(ac[1].substring(6, 8)));
//		int hour = (Integer.parseInt(ac[2].substring(0, 2)));
//		int min = (Integer.parseInt(ac[2].substring(3, 5)));
//		Accident acc = new Accident(ac[0],ac[1],ac[2]);
//		if(!DateCheck(month, date, hour, min)) {
//			System.out.println("��¥/�ð��� �߸� �Է��߽��ϴ�.");
//		}else {
//			accidentHis.add(acc);
//		}
//	}
	
	
	public void addFixHis(String date, String item, String fixcmt) throws Exception { // 수리이력을 추가한다. item : 수리부품 , HashMap
//		 - date별 item(수리부품)의 fixcmt(수리이력)을 추가한다
//       - 조건1 : date별 item(수리부품)은 중복될 수 없다(같은날 같은 엔진)
		
		FixHis fh = new FixHis(date, item, fixcmt);
		
		String strKey = date + "/" + item;
		//System.out.println(strKey); //20190717/범퍼
		String strFixinfo = date + "/" + item + "/" + fixcmt;
		if(fixHis.containsKey(strKey)) {
			throw new Exception("같은 수리부품은 중복 될 수 없습니다.");
		}
		else{
			fixHis.put(strKey, strFixinfo);
		}
		
	}
	
	public void printFixHis() { // 수리이력을 출력한다. HashMap
//		 - 날자 ? 부분 ? 수리Cmt를 출력한다
		Set set = fixHis.entrySet(); // HashMap에 넣은 Key와 Value를 Set에 넣고 iterator에 값으로 Set정보를 담에 준다.
		Iterator it = set.iterator();
		
		while(it.hasNext()) {
			Entry e = (Entry) it.next(); // Entry 객체를 이용하면 key 와 value를 동시에 구할 수 있다
			System.out.println(e.getValue()); // values() --> 저장된 모든 값 출력
		}
	}
	
}

class Util{
	public static boolean validationDate(String date) {
		//setLenient(boolean lenient) :날짜가 파싱될 때 허술하게 할지말지를 설정.
		//이렇게 체크할 경우, 유효한 날짜가 아니면 ParseException을 던질것이고, 유효한 날짜라면 true로 반환.
		try {
			SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMdd HH:mm");
			dateformat.setLenient(false);
			dateformat.parse(date);
			return true;
		}catch(ParseException e) {
			return false;
		}
		
	}
}


class AccidentHis{
	String location;
	String date;
	String time;
	
	AccidentHis(String location, String date, String time){
		this.location = location;
		this.date = date;
		this.time = time;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public String getTime() {
		return time;
	}

	public void setTime(String time) {
		this.time = time;
	}
	
	public int hashCode() {
		return Objects.hash(location, date, time);
	}
	
	public boolean equals(Object obj) {
		if (obj != null && obj instanceof AccidentHis) { // obj가 AccidentHis의 Instance
			return location.equals(((AccidentHis) obj).location) && date.equals(((AccidentHis) obj).date) && time.equals(((AccidentHis) obj).time); // 값이 같은지 비교
		} else {
			return false;
		}
	}

}

class FixHis{
	String date;
	String item;
	String fixcmt;
	
	FixHis(String date, String item, String fixcmt){
		this.date = date;
		this.item = item;
		this.fixcmt = fixcmt;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public String getItem() {
		return item;
	}

	public void setItem(String item) {
		this.item = item;
	}

	public String getFixcmt() {
		return fixcmt;
	}

	public void setFixcmt(String fixcmt) {
		this.fixcmt = fixcmt;
	}
	
	public boolean equals(Object obj) {
		if (obj != null && obj instanceof FixHis) {
			String thisTmp = date + "/" + item;
			String tmp = ((FixHis)obj).getDate() + "/" + ((FixHis)obj).getItem();
			
			return thisTmp.equals(tmp);
		} 
		else return false;		
	}
	
	public int hashCode() {
		return Objects.hash(date, item, fixcmt);
	}
	
}

public class 실습9일차 {

	public static void main(String[] args) throws Exception {
		
		Car car = new Car("말리부", 3000, 10000, "홍길동");
		
		car.addAccidentHis();
		try {
			car.addAccidentHis();  // 오류메세지 출력용	
		}catch (Exception e) {
		e.printStackTrace();
		}
		
		car.printAccidnetHis();
		
		car.addFixHis("20190719", "와이퍼", "교체");
		car.printFixHis();
		try {
			car.addFixHis("20190719", "와이퍼", "교체"); // 오류메세지 출력용	
		}catch (Exception e) {
		e.printStackTrace();
		}
		
		
	}

}
--------------------------------------------------------------------------

package Week02.day0719;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;

class Plane{
	private String model;
	private String airline; //항공사이름
	private HashSet fixHis1 = new HashSet(); // 수리이력
	
	Plane(String model, String airline){
		this.model = model;
		this.airline = airline;
	}
	
	public void addFixHis(String info) throws Exception { // 수리이력을 추가한다 - 같은 수리이력을 추가할 수 없다(airport/date/cmt)
		String data[] = info.split("/");

		try {
			FixHis1 ac = new FixHis1(data[0], data[1], data[2]);
			if(fixHis1.contains(ac))
				throw new Exception("같은 수리이력은 추가 될 수 없습니다.");
			else
				fixHis1.add(ac);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public void printFixtHis() { // 수리이력을 출력한다. -  - 수리이력을 출력: 공항-날자-사고내용
		Iterator it = fixHis1.iterator();
		
		while(it.hasNext()) {
			FixHis1 e = (FixHis1) it.next();
			System.out.println(e.getAirport() +"-"+ e.getDate() +"-"+ e.getCmt());
		}
	}
}

class FixHis1{ //set은 hashcode와 equals를 재정의해야함.
	private String airport; // 공항
	private String date; // 수리일자
	private String cmt; // 수리내용
	
	FixHis1(String airport, String date, String cmt){
		this.airport = airport;
		this.date = date;
		this.cmt = cmt;
	}

	public String getAirport() {
		return airport;
	}

	public void setAirport(String airport) {
		this.airport = airport;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public String getCmt() {
		return cmt;
	}

	public void setCmt(String cmt) {
		this.cmt = cmt;
	}
	
	public boolean equals(Object obj) {
		if (obj != null && obj instanceof FixHis1) {
			String thisTmp = airport + date + cmt;
			String tmp = ((FixHis1) obj).getAirport() + ((FixHis1) obj).getDate() + ((FixHis1) obj).getCmt();
			return thisTmp.equals(tmp);
		} else
			return false;
	}
	
	public int hashCode() { // 추가할수록 값이 디테일하게 쪼개짐.
		return Objects.hash(airport, date, cmt);
	}
}

public class 실습9일차2번 {

	public static void main(String[] args) {
		
		Plane pl = new Plane("보잉707", "아시아나");
		
		try {
		pl.addFixHis("인천공항/20190701/타이어교체");
		pl.addFixHis("나하공항/20190601/날개교체");
		pl.addFixHis("인천공항/20190701/타이어교체");
		pl.printFixtHis();
		} catch(Exception e) {
			e.printStackTrace();
		}
		

	}

}
--------------------------------------------------------------------------

package Week02.day0719;

public class ThreadEx1 {

	public static void main(String[] args) {
		
		//싱글 스레드
		long startTime = System.currentTimeMillis();
		
		for(int i=0; i<500; i++)
			System.out.printf("%s", new String("-"));
		
		System.out.print("소요시간1:" + (System.currentTimeMillis()-startTime)); // 소요시간1:32
		
		for(int i=0; i<500; i++)
			System.out.printf("%s", new String("|"));
		
		System.out.print("소요시간2:" + (System.currentTimeMillis()-startTime)); // 소요시간2:43

	}

}
--------------------------------------------------------------------------
/* Multi Threading */
1. 여러 Thread가 하나의 자원을 공유
2. Monitors
- Monitor란 상태변수
- Monitors는 일종의 열쇠, 임계영역(critical section)을 들어가기 위해선 이 열쇠가 필요하다.
- 임계영역을 만들기 위해 synchronized 키워드를 사용한다.

package Week02.day0719;

public class ThreadEx2 {
	
	static long startTime = 0;

	public static void main(String[] args) {
		
		//멀티스레드
		ThreadEx2_1 th1 = new ThreadEx2_1();
		th1.run();
		startTime = System.currentTimeMillis();
		
		for(int i=0; i<300; i++) {
			System.out.print("-");
		}

		System.out.print("소요시간2:" + (System.currentTimeMillis()- ThreadEx2.startTime)); // 소요시간2:2
	}

}


class ThreadEx2_1 extends ThreadEx2{
	public void run() {
		for(int i=0; i<300; i++) {
			System.out.print("|");
		}
		
		System.out.print("소요시간2:" + (System.currentTimeMillis()- ThreadEx2.startTime)); // 소요시간2:1563517789948
	}
}

--------------------------------------------------------------------------
package Week02.day0719;

public class ThreadSwtiching {

	public static void main(String[] args) {
		//ThreadSwtiching 예제
		/*앞에서 만든 쓰레드 B를 만든 후 Start
		 * 해당 쓰레드가 실행되면, 해당 쓰레드는 run메소드안에서 자신의 모니터링 락을 획득
		 */
		
		ThreadB b = new ThreadB();
		b.start();
		//b에 대하여 동기화 블럭을 설정
		//만약 main 쓰레드가 wait을 하게 되면서 main쓰레드 대기
		synchronized(b) { // synchronized{} : 동기화 처리부분
			try {
				//b.wait()메소드를 호출.
				//메인쓰레드는 정지
				//ThreadB가 5번 값을 더한 후 norify를 호출하게 되면 wait에서 깨어남
				System.out.println("b가 완료될 때까지 기다립니다.");
				b.wait();
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
			//깨어난 후 결과를 출력
			System.out.println("Total is : " + b.total);
		}
	}
}

class ThreadB extends Thread{
	/*해당 쓰레드가 실행되면 자기 자신의 모니터링 락을 획득
	 * 5번 반복하면서 0.5초씩 쉬면서 total에 값을 누적
	 * 그 후에 notify()메소드를 호출하여 wait하고 있는 쓰레드를 깨움
	 */
	
	int total;
	public void run() {
		synchronized(this) {
			for(int i=0; i<5; i++) {
				System.out.println(i + "를 더합니다.");
				total+=i;
				try {
					Thread.sleep(500);
				} catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
			notify();
		}
	}
}

//출력값
//b가 완료될 때까지 기다립니다.
//0를 더합니다.
//1를 더합니다.
//2를 더합니다.
//3를 더합니다.
//4를 더합니다.
//Total is : 10

--------------------------------------------------------------------------

package Week02.day0719;

public class SyncThread {

	public static void main(String[] args) {
		
		//동기화 적용예제
		
		User user = new User();
		
		//3개의 스레드 객체 생성
		UserThread p1 = new UserThread(user, "A1");
		UserThread p2 = new UserThread(user, "B2");
		UserThread p3 = new UserThread(user, "C3");
		
		//스레드 스케줄링 : 우선순위 부여
		p1.setPriority(p1.MAX_PRIORITY);
		p2.setPriority(p3.NORM_PRIORITY);
		p3.setPriority(p3.MIN_PRIORITY);

		System.out.println("----------------------");
		System.out.println("sychronized 적용안한 경우");
		System.out.println("----------------------");
		
		//스레드 시작
		p1.start();
		p2.start();
		p3.start();
	}
}

//Heap영역의 멤버 변수는 공통으로 사용
class User{
	private int userNo = 0;
	
	//임계 영역을 지정하는 sychronized메소드
	public void add(String name) {
		System.out.println(name + ":" + userNo++ + "번째 사용"); //  sychronized 가 없으므로, 랜덤값이 출력됨.
	}
}

class UserThread extends Thread{
	User user;
	
	UserThread(User user, String name){
	super(name);
	this.user = user;
	}
	
	public void run() {
		try {
			for(int i=0; i<3; i++) {
				user.add(getName());
				sleep(500);
			}
		}catch(InterruptedException e) {
			System.err.println(e.getMessage());
		}
	}
}

//출력값
//----------------------
//sychronized 적용안한 경우
//----------------------
//A1:0번째 사용
//B2:1번째 사용
//C3:2번째 사용
//A1:3번째 사용
//C3:3번째 사용
//B2:3번째 사용
//A1:4번째 사용
//C3:5번째 사용
//B2:4번째 사용

--------------------------------------------------------------------------

package Week02.day0719;

public class SyncThread2 {

	public static void main(String[] args) {
		
		//동기화 적용예제
		
		User2 user = new User2();
		
		//3개의 스레드 객체 생성
		UserThread2 p1 = new UserThread2(user, "A1");
		UserThread2 p2 = new UserThread2(user, "B2");
		UserThread2 p3 = new UserThread2(user, "C3");
		
		//스레드 스케줄링 : 우선순위 부여
		p1.setPriority(p1.MAX_PRIORITY);
		p2.setPriority(p3.NORM_PRIORITY);
		p3.setPriority(p3.MIN_PRIORITY);

		System.out.println("----------------------");
		System.out.println("sychronized 적용한 경우");
		System.out.println("----------------------");
		
		//스레드 시작
		p1.start();
		p2.start();
		p3.start();
	}
}

//Heap영역의 멤버 변수는 공통으로 사용
class User2{
	private int userNo = 0;
	
	//임계 영역을 지정하는 sychronized메소드
	//메소드 내 작업이 완료될 때까지 다른 Thread가 들어올 수 없다.
	public synchronized void add(String name) {
		System.out.println(name + ":" + userNo++ + "번째 사용");
	}
}

class UserThread2 extends Thread{
	User2 user;
	
	UserThread2(User2 user, String name){
	super(name);
	this.user = user;
	}
	
	public void run() {
		try {
			for(int i=0; i<3; i++) {
				user.add(getName());
				sleep(500);
			}
		}catch(InterruptedException e) {
			System.err.println(e.getMessage());
		}
	}
}

//출력값
//----------------------
//sychronized 적용한 경우
//----------------------
//A1:0번째 사용
//B2:1번째 사용
//C3:2번째 사용
//B2:3번째 사용
//A1:4번째 사용
//C3:5번째 사용
//B2:6번째 사용
//C3:7번째 사용
//A1:8번째 사용


And