네트워크 프로그래밍

java.net.InetAddress 클래스

- InetAddress 클래스는 인터넷상의 IP 주소를 객체 모델링한 클래스로 IP주소와 관련된 여러 정보를 제공하는 클래스이다.

 

Ex001_InetAddress >>

더보기
package netEx;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;

public class Ex001_InetAddress {

	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String host = null;
		
		try {
			System.out.print("호스트명[www.naver.com 또는 컴이름] ? ");
			host = br.readLine();
			
			InetAddress ia = InetAddress.getByName(host);
			
			String str = ia.getHostName();
			String ip = ia.getHostAddress();
			
			System.out.println("호스트명 : "+str);
			System.out.println("아이디 : "+ip);
			
		} catch (Exception e) {
			e.printStackTrace();
		} 

	}

}

위 예제를 통해 InetAddress 클래스로 해당 주소의 호스트명과 ip를 가져올 수 있었다.

 


URL(Uniform Resource Locator) 이란?

- URL은 네트워크 상에서 자원이 어디 있는지를 알려주기 위한 규약이다.

- URL은 웹 사이트 주소뿐만 아니라 컴퓨터 네트워크 상의 자원을 모두 나타낼 수 있다.

- URL 구성

 프로토콜://호스트:[포트번호]/[파일]#[세션]

 

java.net.URL 클래스

- URL 클래스는 웹(World Wide Web) 상에 존재하는 자원(resource)에 접근하기 위해, 자원의 유일한 주소를 나타내기 위한 기능을 제공해 주는 클래스이다.

- 자원이란 파일 또는 디렉토리와 같은 간단한 것에서부터 데이터베이스 또는 서치엔진에 대한 쿼리(query)와 같은 복잡한 형태의 객체일 수도 있다.

 

java.net.URLConnection 클래스

- URLConnection 클래스는 추상 클래스로 애플리케이션과 URL 간의 통신 링크를 위한 모든 클래스들에 대한 상위 클래스이다.

- URLConnection 객체는 URL을 이용하여 참조된 자원에 대해 읽고 쓰는 작업을 할 수 있도록 해준다.

 

URLEncoder 와 URLDecoder 클래스

- application/x-www-form-urlencoded 는 HTML form 데이터 기본 전송 방식이다.

영문자 숫자('a'~'z', 'A'~'Z', '0'~'9')는 그대로 표현된다.

특수 문자의 '.'. '-', '*', '_' 는 그대로 표현된다.

공백 문자(' ')는 '+' 기호로 변환된다.

기타 문자는 %xy와 같이 세 개의 문자로 변환되는데, 이 때 xy는 문자의 하위 8비트에 대한 16진수 두자리를 나타낸다.

- MIME(Multipurpose Internet Mail Extensions) type : 메세지 컨텐트 형식을 정의하기 위한 인터넷 표준을 의미한다.

 

java.net.URLEncoder 클래스

- HTML 형식을 encode하기 위한 유틸리티 클래스로 문자열을 application/x-www-form-urlencoded MIME 형식으로 변환하기 위한 static 메소드를 제공한다.

 

java.net.URLDecoder 클래스

- HTML 형식을 디코드하기 위한 유틸리티 클래스로, applicaion/x-www-form-urlencoded MIME 형식을 문자열로 디코드 하기위한 static 메소드를 제공한다.

 

Ex002_URL >>

더보기
package netEx;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

public class Ex002_URL {

	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String webUrl, s;

		BufferedReader nbr = null;

		try {
			System.out.print("웹주소[https://www.naver.com] ? ");
			webUrl = br.readLine();
			
			// URL : 웹(World Wide Web)상의 리소스에 대한 포인터를 나타냄
			URL url = new URL(webUrl);
			InputStream is = url.openStream();
			
			nbr = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			
			while( (s = nbr.readLine()) !=null) {
				System.out.println(s);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (nbr != null) {
				try {
					nbr.close();
				} catch (Exception e2) {
				}
			}
		}

	}

}

아직 뭔지 모르는 소스들을 가져왔다.

 

Ex003_URLEncoder >>

더보기
package netEx;

import java.net.URLDecoder;
import java.net.URLEncoder;

public class Ex003_URLEncoder {

	public static void main(String[] args) {
		String s1, s2;
		s1 = "자바 java";
		
		try {
			// 인터넷에서 데이터를 전송할 수 있는 상태로 변환(application/x-www-form-urlencoded)
			s2 = URLEncoder.encode(s1, "UTF-8");
			System.out.println(s2); // %EC%9E%90%EB%B0%94+java

			// 주소형식으로 변환된 문자열을 다시 원래대로 변환
			s1 = URLDecoder.decode(s2, "UTF-8");
			System.out.println(s1);
			
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

URLEncoder 와 URLDecoder 클래스로 문자열을 인터넷에서 주고받을 수 있는 형태로 변환해보고 다시 변환된 것을 우리가 볼 수 있도록 바꾸어보았다.

 

동기화 ?

더보기

동기화란?

- 멀티 스레드(Multi Thread) 환경에서는 여러 스레드가 동일한 프로세스 내의 자원을 공유해서 사용하기 때문에 문제점이 발생할 수 있다.

- 따라서 공유 자원에 여러 개의 스레드가 동시에 접근하지 못하도록 설정하여야 하는데 이를 동기화라 한다.

- 즉, 한 스레드가 동기화된 객체를 사용하는 경우 오직 그 스레드 만이 그 객체에 접근할 수 있도록 한다.

 

크리티컬 섹션(Critical Section, 임계 영역)

공유 데이터나 리소스(메모리나 파일)에 대한 접근을 하나의 스레드로 제한한다. 즉, 동일한 프로세스 내의 스레드 간 동기화에 사용한다.

뮤텍스(Mutex) 

크리티컬 섹션과 동일한 기능을 가지지만 차이가 있다면 다른 프로세스에 속한 스레드를 제어할 수 있다.

세마포어(Semaphore) 

뮤텍스와 유사하지만 동시에 수행할 수 있는 스레드를 여러 개로 제한할 수 있다.

모니터(Monitors) 

두 개의 스레드에 의해 공유되고 그 값이 참조될 때 반드시 동기화되어야 하는 공유 데이터와 같은 객체를 상태변수(condition variables)라고 한다. 자바 언어에서는 상태 변수에 대한 모니터를 사용할 수 있도록 함으로써 스레드를 동기화 한다. 모니터는 자신이 소유한 스레드를 제외한 다른 스레드의 접근을 막는다.

교착 상태(DeadLock)

두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있기 때문에 결과적으로 아무 것도 완료되지 못하는 상태를 가리킨다.

 

Synchronized 키워드

- Synchronized 키워드를 통해 해당 작업과 관련된 공유 데이터에 lock을 걸어서 먼저 작업 중이던 스레드가 작업을 완전히 마칠 때까지는 다른 스레드에게 제어권이 넘어가더라도 데이터가 변경되지 않도록 보호함으로써 스레드의 동기화를 가능하게 한다.

Ex001, Ex003 : 동기화하지 않은 경우

더보기
package threadEx2;

public class Ex001_Synchronized {
	public static void main(String[] args) {
		MyBank1 b = new MyBank1();
				
		Thread t1 = new Thread(b);
		Thread t2 = new Thread(b);
		
		t1.start();
		t2.start();
	}
}

// 동기화 하지 않은 경우
class MyBank1 implements Runnable {
	private int money = 10000;
	
	
	@Override
	public void run() {
		int need = 6000;
		int n = 0;
		String msg = null;
		
		try {
			if(getMoney()>=need) {
				Thread.sleep(200);
				n = drawMoney(need);
				msg = "인출 성공";
			} else {
				n = 0;
				msg = "인증 실패";
			}
			
			System.out.println(msg + ", 인출금액:"+n+", 잔고:"+getMoney());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}


	public int getMoney() {
		return money;
	}


	private int drawMoney(int m) {
		money -= m;
		return m;
	}
}
package threadEx2;

public class Ex003_Synchronized {
	public static void main(String[] args) {
		ShareData1 share = new ShareData1();
		
		UpThread1 t1 = new UpThread1(share, "up");
		DownThread1 t2 = new DownThread1(share, "down");
		
		t1.start();
		t2.start();
		
	}
}

// 동기화 하지 않은 경우
class ShareData1 {
	private int num = 100;
	
	public void up(String title) {
		System.out.print(title+":"+num);
		num++;
		System.out.println(", 증가->"+num);
	}
	public void down(String title) {
		System.out.print(title+":"+num);
		num--;
		System.out.println(", 감소->"+num);
	}
}

class UpThread1 extends Thread {
	private ShareData1 share;
	private String title;
	
	public UpThread1(ShareData1 share, String title) {
		this.share = share;
		this.title = title;
	}
	
	public void run() {
		for(int i=0; i<5; i++) {
			try {
				sleep(500);
				share.up(title);
			} catch (Exception e) {
			}
		}
	}
}

class DownThread1 extends Thread {
	private ShareData1 share;
	private String title;
	
	public DownThread1(ShareData1 share, String title) {
		this.share = share;
		this.title = title;
	}
	
	public void run() {
		for(int i=0; i<5; i++) {
			try {
				sleep(500);
				share.down(title);
			} catch (Exception e) {
			}
		}
	}
}

Ex002, Ex004 : 동기화한 경우

더보기
package threadEx2;

public class Ex002_Synchronized {
	public static void main(String[] args) {
		MyBank2 b = new MyBank2();
				
		Thread t1 = new Thread(b);
		Thread t2 = new Thread(b);
		
		t1.start();
		t2.start();
	}
}

// 동기화 한 경우
class MyBank2 implements Runnable {
	private int money = 10000;
	
	
	@Override
	public void run() {
		int need = 6000;
		int n = 0;
		String msg = null;
		
		try {
			synchronized (this) { // 동기화 블럭
				if(getMoney()>=need) {
					Thread.sleep(200);
					n = drawMoney(need);
					msg = "인출 성공";
				} else {
					n = 0;
					msg = "인증 실패";
				}				
			}
			
			System.out.println(msg + ", 인출금액:"+n+", 잔고:"+getMoney());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}


	public int getMoney() {
		return money;
	}


	private int drawMoney(int m) {
		money -= m;
		return m;
	}
}

Ex005_wait : 대기

더보기
package threadEx2;

public class Ex005_wait {
	public static void main(String[] args) {
		MyBank3 atm = new MyBank3();
		
		Thread t1 = new Thread(atm, "t1");
		Thread t2 = new Thread(atm, "t2");
		
		t1.start();
		t2.start();
		
	}
}

class MyBank3 implements Runnable {
	private long money = 10000;
	
	public void run() {
		synchronized (this) {
			for(int i = 0; i < 10; i++) {
				if(getMoney() <= 0) {
					// wait()에 의해 대기하고 있는 모든 스레드를 깨운다.
					this.notifyAll();
					break;
				}
				
				drawMoney(1000);
				
				if(getMoney()>=2000 && getMoney() % 2000 == 0) {
					try {
						// wait()를 만나면 해당 쓰레드는 해당 객체의 모니터링 락에 대한 권한을 가지고 있으면
						// 모니터링 락의 권한을 놓고 대기한다.
						// synchronized 블록에서만 사용
						this.wait();
					} catch (Exception e) {
					}
				} else {
					// wait()에 의해 대기하고 있는 해당 스레드를 깨운다.
					// 아래 notify()를 주석 처리하면 무한 대기(deadlock)상태가 된다.
					this.notify();
				}
				
			}
			
		}
	}

	public long getMoney() {
		return money;
	}
	
	public void drawMoney(long m) {
		System.out.print(Thread.currentThread().getName()+", "); // 현재 쓰레드명 출력
		
		if(getMoney()>=m) {
			money -= m;
			System.out.printf("잔액 :  %,d원\n", getMoney());
		} else {
			System.out.println("잔액이 부족 합니다.");
		}
	}
}

 

스레드 우선순위

더보기

- 자바의 스레드 스케쥴링은 우선순위(Priority)방식과 라운드 로빈(Round-robin) 방식을 사용한다.

1) 우선순위(Priority) 방식

- 우선순위가 높은 스레드가 실행 상태를 더 많이 가지도록 스케쥴링 하는 것

- 우선순위를 부여하여 코드로 제어가 가능하다.

2) 라운드 로빈(Round-robin) 방식

- 시간 할당량(Time Slice)을 정해서 스레드를 정해진 시간만큼 실행시키고 다른 스레드를 실행하는 방식

- JVM에 의해 정해지므로 코드로 제어할 수 없다.

 

- 스레드는 우선순위를 나타내는 필드(priority)를 가지고 있다. 1~10 사이의 값을 갖는다. (10: 가장 높음)

- 자바 런타임 스케줄러는 현재 실행 가능한 스레드들 중에서 우선순위가 가장 높은 스레드를 실행시켜 주는데, 현재 실행중인 스레드보다 더 높은 우선순위를 갖는 스레드가 실행가능 상태가 되면 자바 런타임 스케줄러는 우선순위가 더 높은 스레드를 실행시켜 준다.

- 스레드 우선 순위는 스레드를 생성한 스레드로부터 상속 받는다. main() 메소드에서 스레드를 생성하면 main() 메소드의 우선 순위가 5이므로 자동으로 5를 갖는다.

Ex007_Priority >>

더보기
package threadEx;

public class Ex007_Priority {
	public static void main(String[] args) {
		MyThread7 t1 = new MyThread7("A");
		MyThread7 t2 = new MyThread7("B");
		MyThread7 t3 = new MyThread7("C");

		t1.setPriority(Thread.MIN_PRIORITY); // 1
		t2.setPriority(Thread.MAX_PRIORITY); // 10
		
		t1.start();
		t2.start();
		t3.start();
		
	}
}

class MyThread7 extends Thread {
	public MyThread7(String name) {
		super(name);
	}

	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			// System.out.println(getName() + " -> " + i);
			System.out.println(this); // [스레드명, 우선순위, 그룹]
		}

	}
}

몇 번 실행시켜보면 우선순위가 높은 B부터 일처리를 하는 것을 알 수 있다.

 

데몬 스레드(Daemon Thread)

- 일반 스레드는 자신의 작업을 수행하도록 되어 있는 반면, 데몬 스레드란 일반 스레드로 부터 요청을 받아 특정 서비스를 수행하는 작업을 한다.

- 즉, 다른 일반 스레드를 돕는 보조적인 역할을 하는 스레드이다.

- 일반 스레드가 모두 종료되면 데몬 스레드도 자동 종료된다.

- 데몬 스레드가 생성한 스레드는 자동으로 데몬 스레드가 된다.

- 예를 들어, 가비지 컬렉터, 워드 프로세스의 자동 저장 등 백그라운드에서 특별한 작업을 처리하는 용도로 사용한다.

 

Ex006_Daemon Thread  >>

더보기
package threadEx;

/*
 - 독립 스레드
 	메인은 프로그램의 시작점이지 종료점은 아니다. 
 	메인 스레드가 종료되어도 독립 스레드의 작업이 완료될 때까지 프로그램은 종료되지 않는다.
 - 데몬 스레드
 	다른 스레드에게 도움을 주기 위한 스레드
 	메인 스레드가 종료되면 데몬 스레기의 작업이 완료되지 않아도 프로그램은 종료됨.
 */
public class Ex006_Daemon {
	public static void main(String[] args) {
		MyThread6 t1 = new MyThread6();
		MyThread6 t2 = new MyThread6();
		MyThread6 t3 = new MyThread6();

		// 스레드들 데몬으로 만듦
		t1.setDaemon(true);
		t2.setDaemon(true);
		t3.setDaemon(true);
		
		t1.start();
		t2.start();
		t3.start();
		
		try {
			t1.join(); // 스레드가 종료될 때 까지 대기
			t2.join();
			t3.join();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("메인 종료...");
	}
}

class MyThread6 extends Thread {
	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			System.out.println(getName() + " -> " + i);
			
			try {
				Thread.sleep(500);
			} catch (Exception e) {
			}
		}
		
	}
}

메인이 종료되면 같이 종료된다.

Ex005_Runnable : 1초마다 찍는 스레드

더보기
package threadEx;

import java.util.Calendar;

public class Ex005_Runnable {

	public static void main(String[] args) {
		Thread t = new Thread(new MyThread5());
		t.start();

	}

}

class MyThread5 implements Runnable {

	@Override
	public void run() {
		String str;

		while (true) {
			Calendar cal = Calendar.getInstance();

			str = String.format("%tF %tT", cal, cal);
			System.out.println(str);

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

}

Thread.sleep(1000); 괄호 안에는 millisecond 단위이므로 1000이면 1초를 뜻한다.

terminate를 누르지 않으면 계속 시간이 찍힌다.

Ex006_Runnable : 윈도우창을 활용한 1초마다 시간이 바뀌게 하는 예제 [JFrame 상속 후 Runnable 인터페이스 구현]

더보기
package threadEx;

import java.awt.BorderLayout;
import java.util.Calendar;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Ex006_Runnable {
	public static void main(String[] args) {
		ChatForm cf = new ChatForm();
		Thread t = new Thread(cf);
		t.start();
	}
}

class ChatForm extends JFrame implements Runnable {
	private static final long serialVersionUID = -5166274042184939576L;
	
	private JTextField tf = new JTextField();
	private JTextArea ta = new JTextArea();
	
	public ChatForm() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JScrollPane sp = new JScrollPane(ta);
		add(sp, BorderLayout.CENTER);
		
		add(tf, BorderLayout.SOUTH);
		
		setTitle("채팅...");
		setSize(500,500);
		setVisible(true);
		
		
	}

	@Override
	public void run() {
		String s;
		while(true) {
			try {
				Calendar cal = Calendar.getInstance();
				s = String.format("%tF %tT", cal, cal);
				setTitle(s);
			} catch (Exception e) {
			}
		}
		
	}
	
}

위 코드를 실행하면 이렇게 따로 윈도우창이 뜨고 창 제목이 시스템 시간에 따라 1초씩 찍히는 것을 확인할 수 있다. 

 

프로세스와 스레드

>>

더보기

프로세스 Process

- 운영체제로부터 자원을 할당받은 작업의 단위로, 실행중인 하나의 프로그램을 의미한다.

- 리소스(resource)와 스레드(thread)로 구성된다.

- Code, Data, Heap, Stack영역으로 이루어지며, 각각의 메모리 공간을 차지한다.

- 동시에 두 개 이상의 프로그램을 특정 기법으로 동시에 실행시키는 기능을 멀티 태스킹(multitasking) 이라 한다. 특정 기법에는 대표적으로 시분할(Time-Shared)기법이 있다.

 

스레드 Thread

- 프로세스 내에서 실행되는 흐름의 단위이다. 즉, 프로세스가 할당 받은 자원을 이용하는 실행 단위(흐름)이다. 

- 스레드는 프로세스 내에 존재하며, 모든 프로세스는 적어도 하나이상의 스레드를 가지고 있다.

- 프로세스는 자신만의 메모리 공간과 자원을 할당받아 사용하지만, 스레드는 다른 스레드와 메모리와 자원을 공유한다.

Code, Data, Heap 영역은 공유하고 별도의 Stack영역만 가지고 있다.

- 둘 이상의 스레드를 가진 프로세스를 멀티 스레드 프로세스(multi-thread process)라 한다.

 

멀티 스레드 

장점

- 시스템의 자원소모가 줄어든다.

- CPU의 사용률을 향상시킨다.

- 프로그램의 응답 시간이 단축된다.

 

단점

- 자원 공유를 위해 전역변수를 이용하므로 동기화 관련된 문제가 발생할 수 있다.

- 잘못된 변수를 사용하거나 미묘한 시간차로 인해 프로그램에 오류가 발생할 수도 있다.

- 디버깅이 어렵다.

스레드 구현 및 실행

>>

더보기

자바 메인 스레드

- 자바는 프로그램(process)이 시작되면 기본적으로 main() 메소드를 진입점(Entry Point)으로 하는 메인 스레드(Main Thread)가 생성되며, 사용자가 정의한 스레드를 생성함으로써 멀티 스레드를 구현할 수 있다.

- main()메소드는 프로그램의 진입점이지 종료점이 아니므로, 멀티 스레드 환경에서는 모든 스레드가 종료되야 프로세스가 종료된다.

 

java.lang.Thread 클래스

- 스레드 생성 및 시작, 관리를 위한 클래스이다.

- Thread 클래스를 상속 받은 하위 클래스에서 run() 메소드를 재정의하여 스레드를 구현한다.

 

java.lang.Runnable 인터페이스

- 스레드에서 실행할 코드를 가지는 run() 메소드가 선언되어 있다.

- 자바는 단일 상속만 구현 가능하므로 스레드를 구현할 클래스가 다른 클래스를 상속 받은 경우 Runnable 인터페이스를 구현한다.

- Runnable 인터페이스를 implements 한 클래스는 run() 메소드를 재정의하여 스레드를 구현한다.

 

스레드 시작

- 스레드를 실행하기 위해서는 Thread 클래스의 start() 메소드를 호출하면 스레드를 시작한다. start() 메소드에 의해 스레드가 시작되면, 자바 가상 머신은 이 스레드의 run() 메소드를 호출한다.

- 스레드 시작 방법

 1) Thread 클래스를 상속받는 하위 클래스 만든 경우 : 해당 클래스의 객체를 생성한 후 Thread 클래스의 start() 메소드를 호출한다.

 2) Runnable 인터페이스를 구현하여 클래스를 만든 경우 : Thread(Runnable target) 생성자에 Runnable 인터페이스 구현 클래스 객체를 인수로 넘겨 Thread 클래스의 객체를 생성하여 Thread 클래스의 start() 메소드를 호출한다.

 

스레드 종료

- 스레드의 종료는 run() 메소드가 종료되는 시점이다.

- Thread 클래스의 stop() 메소드를 이용하여 강제로 스레드를 종료할 수 있지만 사용을 권장하지 않는다.

스레드 예제

Ex001_Thread : Thread 클래스를 이용한 스레드 구현 >>

더보기

 

package threadEx;

public class Ex001_Thread {

	public static void main(String[] args) {
		MyThread1 t = new MyThread1();

		t.start(); // 스레드 시작
		// t.run(); // 유저가 부르면 Tread가 아님.
		
		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("main 종료 !!!");
		// main은 프로그램의 시작점이지만 종료점은 아니다.
		// main이 종료되어도 프로그램은 종료되지 않을 수 있다.
		// 프로그램의 종료 시점은 모든 독립스레드가 종료되는 시점이다.
	}
}

// 스레드 구현방법 - 1
//	1) Thread 클래스를 상속 받아 run() 메소드를 override한다.
//	2) Thread 클래스를 상속 받은 클래스의 객체를 생성하여 start() 메소드를 호출한다.
class MyThread1 extends Thread {

	@Override
	public void run() {
		int n = 0;

		try {
			while (n < 20) {
				n++;
				System.out.println(getName() + " -> " + n);

				sleep(500); // 지정 시간(단위:ms)동안 스레드 실행이 일시 중지됨.
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
}

스레드클래스를 상속받아 run() 메소드를 override 해서 클래스의 객체를 생성해서 start()메소드로 멀티 스레드를 구현했다. main 에서도 이미 Thread가 (main() 메소드를 진입점으로 하는 메인 스레드가 존재) 있기 때문에 둘을 비교해보았다.

main()이 종료되어도 프로그램 종료는 모든 독립 스레드가 종료된 후에 일어난다.

Ex002_Runnable : Runnable 인터페이스를 이용한 스레드 구현 >>

더보기
package threadEx;

public class Ex002_Runnable {
	public static void main(String[] args) {
		MyThread2 th = new MyThread2();
		Thread t = new Thread(th);
		t.start();
		
		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("main 종료 !!!");
	}
}

// 스레드 구현방법 - 2
//	1) Runnable 인터페이스를 구현하는 클래스를 만들어 run() 메소드를 override 한다.
//	2) Runnable 인터페이스 구현 클래스 객체를 생성한다.
//	3) Thread 클래스를 객체를 생성하며, Thread 객체를 생성할 때 생성자의 인자에 2)번에서 생성한 객체를 넘긴다.
//	4) 
class MyThread2 implements Runnable {

	@Override
	public void run() {
		int n = 0;

		try {
			while (n < 20) {
				n++;
				System.out.println(Thread.currentThread().getName() + " -> " + n);
				Thread.sleep(500);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

Runnable 인터페이스를 구현하는 클래스를 만들어 run() 메소드를 override한 후 Runnable 인터페이스 구현 클래스 객체를 생성한다. Thread 클래스 객체를 생성하여 생성자의 인자에 Runnable 구현 클래스 객체를 넘겨준다.

Ex003_Runnable : 익명 클래스를 이용한 스레드 구현 >> 

더보기
package threadEx;

public class Ex003_Runnable {

	public static void main(String[] args) {
		// 스레드 구현방법 - 3 : 익명 클래스를 이용한 스레드 구현
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					for (int n = 1; n <= 20; n++) {
						System.out.println("스레드 -> " + n);
						Thread.sleep(500);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		});

		t.start();

		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("메인 -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("메인 종료 !!!");
		
	}

}

익명클래스는 전에 수업시간에 한 번 보고 나서 너무 오랫만에 보는 클래스라 너무 낯설었다.

Ex004_Runnable : 람다를 이용한 스레드 구현 >>

더보기
package threadEx;

public class Ex004_Runnable {

	public static void main(String[] args) {
		// 스레드 구현 방법 - 4 : 람다를 이용한 스레드 구현
		Thread t = new Thread( () -> {
			try {
				for (int n = 1; n <= 20; n++) {
					System.out.println("스레드 -> " + n);
					Thread.sleep(500);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});

		t.start();

		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("메인 -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("메인 종료 !!!");

	}

}

람다는 아직 배우지 않았으므로 그냥 이렇게 구현할 수 있구나~ 정도만 알면 된다고 하셨다.

 

모델링의 정의

- 현실 세계의 정보들을 컴퓨터에 표현하기 위해서 단순화, 추상화 하여 체계적으로 표현한 개념적 모형

- 모델이라고 하는 것은 모형, 축소형의 의미로서 살아가면서 나타날 수 있는 다양한 현상에 대해서 일정한 표기법에 의해 표현해 놓은 모형

- 사람이 살아가면서 나타날 수 있는 다양한 현상은 사람, 사물, 개념 등에 의해 발생된다고 할 수 있으며, 모델링은 이것을 표기법에 의해 규칙을 가지고 표기하는 것 자체

- 정보시스템 구축에서는 모델링을 계획, 분석, 설계 할 때 업무를 분석하고 설계하는데 이용하고 이후 구축, 운영단계에서는 변경과 관리의 목적으로 이용

 

모델링의 특징

- 추상화

  1) 추상화(모형화, 가설적)는 현실세계를 일정한 형식에 맞추어 표현을 한다는 의미

  2) 다양한 현상을 일정한 양식인 표기법에 의해 표현한다는 것

- 단순화 : 복잡한 현실세계를 약속된 규약에 의해 제한된 표기법이나 언어로 표현하여 쉽게 이해할 수 있도록 하는 개념

- 명확화 : 누구나 이해하기 쉽게 하기 위해 대상에 대한 애매모호함을 제거하여 정확하게 현상을 기술하는 것


데이터 모델의 개념

- 현실 세계를 데이터베이스에 표현하는 중간 과정, 즉 데이터베이스 설계과정에서 데이터 구조를 표현하기 위해 사용되는 도구

- 현실 세계의 데이터 구조를 컴퓨터 세계의 데이터 구조로 기술하는 개념적인 도구

- 단순화, 추상화를 제공하기 위해 사용

- 데이터베이스의 구조를 묘사하기 위해 사용되는 개념들의 집합

- 데이터베이스의 구조는 데이터의 타입, 데이터간의 관계, 데이터를 유지하기 위해 필요한 제약들을 의미

 

개념적 데이터의 모델링

- 처음 현실세계에서 추상화 수준이 높은 상위 수준을 형상화하기 위해 개념적 데이터 모델링을 전개

- 추상화 수준이 높고 업무중심적이고 포괄적인 수준의 모델링을 진행한다.

- 속성들로 기술된 개체 타입과 이 개체 타입들 간의 관계를 이용하여 현실 세계를 표현하는 방법

- 요구사항을 수집하고 분석한 결과를 토대로 업무의 핵심적인 개념을 구분하고 전체적인 뼈대를 만드는 과정

- 개체(entity)를 추출하고 각 개체들 간의 관계를 정의하여 E-R 다이어그램을 만드는 과정까지를 말함

 

논리적 모델링 과정

- 개념적 모델링에서 추출하지 않았던 상세 속성들을 모두 추출함

- 정규화 수행

- 데이터 표준화 수행

 

물리적 모델의 개념

- 데이터베이스 저장구조에 따른 테이블스페이스 등을 고려한 방식을 물리적인 데이터 모델링이라고 함

- 레코드의 형식, 순서, 접근 경로와 같은 정보를 사용하여 데이터가 컴퓨터에 저장되는 방법을 묘사

- 작성된 논리적 모델을 실제 컴퓨터의 저장 장치에 저장하기 위한 물리적 구조를 정의하고 구현하는 과정

- DBMS의 특성에 맞게 저장 구조를 정의해야 데이터베이스가 최적의 성능을 낼 수 있음.

- 물리적 모델링 시 트랜잭션, 저장 공간 설계 측면에서 고려할 사항

 1) 응답시간을 최소화

 2) 얼마나 많은 트랜잭션을 동시에 발생시킬 수 있는 지 검토

 3) 데이터가 저장될 공간을 효율적으로 배치


데이터베이스 설계

데이터베이스 생명주기

- 요구조건 분석 : 데이터베이스에 저장할 내용을 정하기 위해 사용자 요구사항 분석

- 설계 : 개념적 설계, 논리적 설계, 물리적 설계

- 구현 : 스키마 정의, 데이터베이스 구축

- 운영 : 사용자의 요구에 맞는 서비스 제공

- 감시 및 개선 : 새로운 요구조건 감시 및 성능 향상

 

package metaEx;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;

import db_util.DBConn;

public class MySqlplus {
	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String sql, s;
		int n;

		gogo: 
		while (true) {
			try {
				System.out.print("SQL> ");
				sql = "";
				n = 1;
				do {
					s = br.readLine();
					if (s == null || s.equalsIgnoreCase("exit")) {
						DBConn.close();
						System.exit(0);
					}

					s = s.trim();
					sql += s + " ";

					if (sql.trim().length() == 0) {
						continue gogo;
					}
					if (s.lastIndexOf(";") == -1) {
						System.out.print((++n) + " ");
					}
				} while (s.lastIndexOf(";") == -1);

				sql = sql.trim();
				sql = sql.substring(0, sql.lastIndexOf(";"));
				if (sql.length() == 0) {
					continue;
				}
				execute(sql);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void execute(String sql) {
		Connection conn = DBConn.getConnection();
		Statement stmt = null;
		ResultSet rs = null;
		ResultSetMetaData rsmd = null;

		try {
			stmt = conn.createStatement();
			if (sql.toUpperCase().startsWith("SELECT")) {
				rs = stmt.executeQuery(sql);
				rsmd = rs.getMetaData();

				int cols = rsmd.getColumnCount();
				for (int i = 1; i <= cols; i++) {
					System.out.print(rsmd.getColumnName(i) + "\t");
				}
				System.out.println();

				for (int i = 1; i <= cols; i++) {
					System.out.print("----------");
				}
				System.out.println();

				while (rs.next()) {
					for (int i = 1; i <= cols; i++) {
						System.out.print(rs.getString(i) + "\t");
					}
					System.out.println();
				}
			} else {
				// INSERT, UPDATE, DELETE, CREATE, ALTER, DROP 등
				int result = stmt.executeUpdate(sql);
				if (sql.toUpperCase().startsWith("INSERT")) {
					System.out.println(result + " 행이 추가 되었습니다.");
				} else if (sql.toUpperCase().startsWith("UPDATE")) {
					System.out.println(result + " 행이 수정 되었습니다.");
				} else if (sql.toUpperCase().startsWith("DELETE")) {
					System.out.println(result + " 행이 삭제 되었슨비다.");
				} else {
					System.out.println("쿼리가 실행 되었습니다.");
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}

			if (stmt != null) {
				try {
					stmt.close();
				} catch (Exception e2) {
				}
			}
		}

	}
}

 

+ Recent posts