- 서버구축 및 운용비용을 절감할 수 있다. - 자원의 활용을 극대화 할 수 있다. - 자원의 관리가 어렵다. - 보안이 취약하다.
1.2 IP주소(IP address)
IP주소는 컴퓨터(호스트, host)를 구별하는데 사용하는 고유한 값. 4 byte(32bit)의 정수로 구성되어있음. a.b.c.d와 같은 형식으로 표현됨. abcd는 0~255사이의 정수이다. 윈도우 콘솔에서 ifconfig를 확인하면 ip주소를 확인 할 수 있음. ex)
ip주소 192.168.10 .100 (네트워크주소).(호스트주소)
서브넷마스크 255.255.255.0
1.3 InetAddress
자바에서 IP주소를 다루기 위한 클래스로 InetAddress 제공함
1.4 URL(Uniform Resource Location)
URL은 인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소를 표현하기 위한것. “프로토콜://호스트명:포트번호/경로명/파이명?쿼리스트링#참조”의 형태로 이루워져있음.
프로세스(process)는 간단하게 말하면 실행중인 프로그램이다. 프로그램 –실행–> 프로세스 프로세스는 데이터, 메모리등의 자원과 쓰레드로 구성되어있음. 프로세스의 자원을 이용해서 실제 작업을 수행하는 것. 모든 프로세스는 최소 하나 이상의 쓰레드가 존재. 둘 이상이면 멀티쓰레드 프로세스라한다.
멀티쓰레딩의 장점
CPU의 사용률을 향상시킴.
자원을 보다 효울적으로 사용할 수 있음.
사용자에 대한 응답성이 향상됨.
작업이 분리되어 코드가 간결해짐.
동기화(synhronization), 교착상태(deadlock)등을 고려해서 신중히 프로그래밍 해야함.
classThreadEx1{ publicstaticvoidmain(String[] args){ ThreadEx1_1 t1 = new ThreadEx1_1(); Runnable r = new ThreadEx1_2(); Thread t2 = new Thread(r); } }
classThreadEx1_1extendsThread{ publicvoidrun(){ for(int i = 0; i < 5; i++) { System.out.println(getName()); } } }
classThreadEx1_2implementsRunnable{ publicvoidrun(){ for(int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()); } } }
쓰레드 생성 후 start()를 호출해야 작업을 시작함. 한번 사용한 쓰레드는 다시 재사용할 수 없다. 하나의 쓰레드에 한번의 start()만 호출 될 수 있음.
1 2 3 4 5 6 7 8 9 10 11
ThreadEx1_1 t1 = new ThreadEx_1(); t1.start(); t.start();//이건 불가능 ```
```java ThreadEx1_1 t1 = new ThreadEx1_1(); t1.start(); t1 = new ThreadEx1_1(); t.start();//이건 가능
3. start()와 run()
run()을 호출하는 것은 생성된 쓰레드를 실행하는 것이 아니라 단순히 클래스에속한 메서드를 하나 호출하는것.
call stack
run
main
start()을 호출하는 것은 새로운 쓰레드가 작업을 실행하는데 필요한 호출스택을 생성한 후 run()을 호출해서 생성된 호출스택에 run()이 저장되게 한다. 모든 쓰레드는 독립적인 작업을 수행하기 위해 자신만의 호출스택을 필요로 하기 때문에 새로운 쓰레드를 생성하고 실행시킬때마다 새로운 호출스택이 생성되고 쓰레드가 종료되면 작업에 사용된 호출스택은 소멸된다.
main메서드에서 쓰레드의 start메서드를 호출한다.
start메서드는 쓰레드가 작업을 수행하는데 사용될 새로운 호출 스택을 생성한다.
생성된 호출스택에 run 메서드를 호출해서 쓰레드가 작업을 수행하도록 한다.
이제는 호츨스택이 2개이기때문에 스케줄러가 정한 순서에 으해 번갈아 가면서 실행된다.
실행중인 쓰레드가 하나도 없을때 프로그램은 종료된다.
4. 싱글쓰레드와 멀티쓰레드
두개의 작업을 하나의 쓰레드로 하면 한 작업 끝난 후 다른 작업 끝. 두개의 작업을 두개의 쓰레드로 하면 짧은시간동안 쓰레드 2개가 번갈아 가면서 작업을 수행해서 동시에 두 작업이 처리되는것과 같다고 느낌. CPU만 사용하는 계산 작업이면 멀티쓰레드가 전환하는 시간때문에 오히려 느림. CPU외 자원을 사용하는 경우 싱글쓰레드 프로세스 보다 멀티쓰레드프로세스가 더 효율적임. ex)외부기기에서 입출력 받는 경우
쓰레드에 우선순위(priority)의 멤버변수가 있다. 우선순위의 범위는 1~10이고 숫자가 높을수록 더 우선순위가 높다. 우선순위의 값은 상대적이다. 1,2와 8,9의 결과 값이 같다. 우선순위는 쓰레드생성한 쓰레드로부터 상속받는다. main 메서드를 수행하는 쓰레드의 우선순위는 5. 파일 다운로드와 채팅기능 중 채팅에 더 우선순위를 높여야 한다.
1 2 3 4 5 6
voidsetPripority(int new Priority); intgetPriority();
classThreadEx15_1{ publicvoidrun(){ for(int i = 0; i < 300 ; i++) { System.out.println("-"); } System.out.println("<<TH1종료>>"); }//run() } classThreadEx15_2{ publicvoidrun(){ for(int i = 0; i < 300 ; i++) { System.out.println("|"); } System.out.println("<<TH2종료>>"); } //run() } ```
왜 th1이 sleep()으로 잠들어있어도 가장 먼저 종료될까? sleep()이 항상 현재 실행중인 쓰레드에 대해 작동해서 th1.sleep()호출해도 main메서드를 실행하는 main쓰레드가 영향받는다. static으로 선언되어 있어서 참조변수로 sleep()을 호출하기 보다는 Thread.sleep()이렇게 호츨해야 함.
## 9. 쓰레드의 동기화 멀티쓰레드는 여러 쓰레드가 같은 프로세스내의 자원을 공유하기 때문에 데이터가 원래 의도했더것과는 다르게 변경 될 수 있음.
### 9.1 synchorized를 이용한 동기화 공유 데이터에 lock을 걸어 먼저 작업중이던 쓰레드가 작업을 완전히 마칠때까지는 다른 쓰레드에게 제어권이 넘어가도 데이터가 변경되지 않도록 보호함.
- synchronized 사용방법 두가지. 가능하면 메서드에 synchronized를 사용하는 메서드 단위 동기화를 권장함.
쓰레드를 동기화 할때 효율을 높이기 위해 사용할 수 있다. 한쓰레드가 lock걸려 다른 쓰레드는 lock이 풀릴때까지 기다려야 되는 상황이 있음. 쓰레드에 lock을 걸는것 대신에 wait()을 호출해서 다른 쓰레드에 제어권을 넘겨주고 대기상태로 기다리다가 다른쓰레드에 의해 notify()가 호출되면 다시 실행상태가 되도록 함 wait()과 notify()는 Object클래스에서 정의되서 모든 객체에서 호출이 가능함. 동기화 블록 내에서만 사용가능. 쓰레드가 wait()을 호출하면 그때까지 걸어 놓은 lock을 풀고 대기실에 들어가기 됨. notify()는 객체의 wating pool에 있는 쓰레드 중 하나만 깨움.
interfaceMovable{ voidmove(int x, int y); } interfaceAttactable{ voidmove(Unit u); }
interfaceFightableextendsMovable, Attackable{}
7.4 인터페이스의 구현
그 자체로는 인스턴스를 생성할 수 없음. 클래스에서 implements를 사용하여 구현함.
1 2 3 4 5 6 7 8 9 10 11
class 클래스 이름 implements 인터페이스이름{ //인터페이스에 정의된 추상메서드 구현 } classFigtherimplementsFightable{ publicvoidmove(int x, int y){ //기능 구현 } publicvoidattack(Unit u){ //기능 구현 } }
구현하는 인터페이스의 메서드 중 일부만 구현하면 추상메서드로 선언되어야 함.
1 2 3 4 5
abstractclassFighterimplementsFigtable{ publicvoidmove(int x, int y){ //기능 구현 } }
자바에서는 다중상속을 허용하지 않아서 인터페이스로 다중상속을 할 수는 있지만 거의 하지 않는다. 두개의 클래스를 상속받아야 하는 상황이라면 두 클래스중 비중이 높은걸 상속받고 나머지는 클래스 내부 멤버로 포함시키는 방법. 필요한 부분을 뽑아 인터페이슬슬 만든 후 구현함.
7.6 인터페이스를 이용한 다형성
인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수있고 형변환도 가능함. 인터페이스 : Fightable, 클래스 : Fighter(implements Figtable)일때
1 2
Fightable f = (Fightable) new Figther(); Fightable f = new Fighter();
인터페이스는 매게변수 타입으로도 쓸 수 있음
1
viod attack(Figtable f){}
메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야한다. 여기서는 new Figther(); 리턴타입으로 인터페이스 타입을 지정하는것도 가능함.
classCastingTest2{ publicstaticvoidmain(String args[]){ Car car = new Car(); Car car2 = null; FireEngine fe = null; car.drive(); fe = (FireEngine) car; //실행시 여기서 에러 발생 fe.drive(); car2 = fe; car2.drive(); } } ```
car가 Car타입의 인스턴스여서 FireEngine을 받을 수 없음. - 캐스트연산자를 사용하면 서로 상속관계에 있는 클래스 타입의 참조변수간의 형변환은 양방향으로 자유롭게 수행될 수 있다. 그러나 참조변수가 참조하고 있는 인스턴스의 자손타입으로 형변환을 하는것은 허용되지 않는다.
### 5.3 instanceof연산자 참조변수가 참조하는 인스턴스 실제타입을 확인하기 위해 instanceof연산자 사용. 주로 조건문에사용. * 값이 ull인 참조변수에 대해 instanceof연산을 하면 false나옴.
```java voiddoWork(Car c){ if(c instanceof FireEngine){ FireEngine fe = (FireEngind) c; fe.water(); } elseif( c instance of Ambulance){ Ambulance a = (Ambulance) c; a.siren(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classInstanceOfTest{ publicstaticvoidmain(String args[]){ FireEngine fe = new FireEngine(); if(fe instanceof FireEngine){ System.out.println("FireEngine instance"); } if( fe instanceof Car){ System.out.println("Car instance"); } if( fe instanceof Object){ System.out.println("Object instance"); } } }
위의 코드를 실행할 경우
1 2 3
FireEngine instance Car instance Object instance
5.4 참조변수와 인스턴스의 연결
멤버변수가 조상클래스와 자손클래스에 중복으로 정의된 경우, 조상 타입의 참조변수를 사용했을 때는 조상클래스에 선언된 멤버변수가 사용되고, 지손타입의 참조변수를 사용했을 때는 자손틀래스에 선언된 멤버변수가 사용된다.
패키지란, 클래스의 묶음. 물리적으로 하나의 디렉터리임. ex) java.lang.String은 java/lang 디렉터리에 위치한 Strig 클래스이다.
하나의 소스파일에는 첫번째 문장으로 단 한번의 패키지 선언만을 허용한다.
모든 클래스는 반드시 하나의 패키지에 속해야 된다.
패키지는 점(.)을 구분자로 하여 계층구조로 구성할 수 있다.
패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉터리다.
3.2 패키지의 선언
1
package 패키지명;
3.3 import 문
import 문은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공함.
3.4 import문의 선언
일반적인 소스 파일(*.java)의 구성은 다음의 순서로 되어있다.
package문
import문
클래스선언
1 2
import 패키지명.클래스명; import 패키지명.*;
4 제어자
4.1 제어자란?
클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여함
접근제어자 - public, protected, default, private
그외 - static, final, abstract, native, transient, synchronized, volatile, strictfp 제어자는 클래스, 멤버변수, 메서드에 주로 사용됨. 하나의 대상에 여러 제어자를 조합하는 것은 가능하나 접근제어자는 하나만 쓸 수 있다.
4.2 static - 클래스의, 공통적인
static 이 사용될 수 있는곳 : 멤머변수, 메서드, 초기화 블럭
*static
대상
의미
멤버변수
- 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다. - 클래스변수는 인스턴스를 생성하지 않고도 가능하다. - 클래스가 메모리에 로드될 때 생성된다.
메서드
- 인스턴스를 생성하지 않고도 호룰이 가능한 static 메서드가 된다. static 메서드 내에선 인스턴스 멤버들을 직접 사용할 수 없다.
1 2 3 4 5 6 7 8 9 10 11 12
classStaticTest{ staticint width =200; staticint height = 120; static { // static 변수의 초기화 수행 } staticintmax(int a, int b){ return a>b?a:b; } }
4.3 final - 마지막의, 변경될 수 없는
final이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수 *final
대상
의미
클래스
변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다. 그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없음
메서드
변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
자손클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수. 조상클래스의 멤버와 자손클래스의 멤버가 중복 정의되서 구별해야 되지 않는 상황이면 super대신 this를 써도 됨. static 메서드(클래스 메서드)에서는 사용 할 수 없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSuperTest{ publicvoidstaticvoidmain(String args[]){ Child c = new Child(); c.method(); } }
classParent{ int x =10; }
classChildextendsParent{ int x =20; voidmethod(){ system.out.println("x="+x); system.out.println("this.x="+this.x); system.out.println("super.x="+super.x); } }
실행 결과
1 2 3
x=20 this.x=20; super.x=10;
2.5 super() - 조상클래스의 생성자
super()는 조상클래스의 생성자를 호출하는 생성자이다. Object클래스를 제외한 모든 클래스의 생성자 첫 줄에는 생성자(같은 클래스의 다른 생성자 또는 조상의 생성자)를 호출 해야함. 그렇지 않으면 컴파일러가 super(); 를 자동으로 첫줄에 삽입.
classProduct{ staticint count =0; //생성된 인스턴스 수를 저장하기 위한 변수 int serialNo; //인스턴스 고유 번호 { ++count; serialNo = count; // Product인스턴스가 생성될 때마다 count 값을 1증가시켜 serialNo에 저장 } publicproduct(){} }