SQLD, ECLIPS, JAVA,PYTHON, NODE....

[Eclips] Java class 10 - 이너클래스 Inners(Nested) class, 스레드Thread, 멀티 스레드 multi Thread, I/O 상속 본문

Java

[Eclips] Java class 10 - 이너클래스 Inners(Nested) class, 스레드Thread, 멀티 스레드 multi Thread, I/O 상속

D_Aiden 2023. 12. 20. 09:11
728x90
반응형
SMALL

2023.12.20

## 내부 클래스(Inner = Nested(중첩) Class )

- 정의: 클래스 내부에 선언된 또다른 클래스
         이름없는 클래스(이벤트 설정 용도)를 호출하기 위함.
- 특징: 내부에 정의된다는 점을 제외하곤, 일반적인 클래스와 다르지 않음.
- 파일저장: workspace > java >bin : 외부클래스$내부클래스$순서(1,2...).class 형태

1. 장점: 클래스를 논리적으로 그룹화 가능.
             패키지를 간소화 할 수 있으며, 유지보수/코드 이해성 측면에선 편리해짐.

// Cat과 Dog 클래스의 외부 클래스
class House {
	int life;
    
// House 클래스의 내부 클래스
    class Cat { 

    }
	
// House 클래스의 내부 클래스
    class Dog {

    }
    
    public void method() {
        Cat animal = new Cat();  //Cat 객체는 반드시 House클래스 메소드 내에서만 사용되고 소멸.
        Dog insect = new Dog();	//Dog 객체는 반드시 House 클래스 메소드 내에서만 사용되고 소멸.
        // ...
    }
}

 

# 타이트한 캡슐화의 적용

내부 클래스에 private 제어자를 적용해 캡슐화를 통해 내부로 숨길 수 있음(코드의 복잡성 감소)

class Creature {
    private int life = 50;
	
    // private class 로, 오로지 Creature 외부 클래스에서만 접근 가능한 내부 클래스로 설정
    private class Animal {
        private String name = "호랑이";

        int getOuter() {
            return life; // 외부 클래스의 private 멤버를 제약 없이 접근 가능
        }
    }

    public void method() {
        Animal animal = new Animal(); 

        // Getter 없이 내부 클래스의 private 멤버에 접근이 가능
        System.out.println(animal.name); // 호랑이

        // 내부 클래스에서 외부 클래스이 private 멤버를 출력
        System.out.println(animal.getOuter()); // 50
    }
}

 

##  내부클래스 종류

내부 클래스 특징
인스턴스 클래스(instance class) 외부 클래스의 멤버변수 선언 위치에 선언. 외부클래스의 인스턴스 멤버처럼 인식.
(외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언)
스테틱 클래스(static class) 외부 클래스의 멤버변수 선언위치에 선언. static 멤버처럼 다뤄짐
(단, static이더라도 new 생성자 초기화를 못하는건 아님)
즉, static 필드변수나 static 메서드 처럼, static 내부클래스 같은 static이나, 메모리 구조와 기능이 전혀 다름.
지역 클래스(local class) 외부 클래스의 메서드나 초기화 블록 안에 선언. 선언된 메소드 블록 내에서만 사용.
익명 클래스(anonymous class) 클래스 선언과 객체 생성을 동시에 하는 이름없는 클래스
(1회용으로 사용할때 자주 이용됨)
class Outer{
	class InstanceInner { ... } 		// 인스턴스 클래스
	static class StaticInner { ... } 	// 스태틱 클래스
    
    void method1(){
    	class LocalInner { ... } 		// 지역 클래스
    }
}

 

# 인스턴스 클래스

- 특징
1) 클래스 멤버변수 선언부에 위치, static 키워드 없는 내부 클래스
2) 외부 클래스의 멤버변수로 취급 되므로 외부 클래스의 객체생성 후, 내부 클래스 객체생성 가능함.
3) 인스턴스 클래스 내부에 instance 멤버만 선언가능(static 맴버는 선언불가)
4) 외부 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언

class PocketBall {
// 인스턴스 변수
    int size = 100;
    int price = 5000;

// 인스턴스 내부 클래스
    class PocketMonster {
        String name = "홍길동";
        int level = 10;
        
// static int cost = 100; 	//에러발생...인스턴스 내부 클래스엔 static의 변수선언 불가.
        static final int cost = 100; 		//final static은 상수이므로 허용

        public void getPoketMember() {
//외부 클래스 맴버 접근 가능
            System.out.println(size);
            System.out.println(price);

//내부 클래스 멤버
            System.out.println(name);
            System.out.println(level);
            System.out.println(cost);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        
        PocketBall ball = new PocketBall(); 		// 먼저 외부 클래스를 인스턴스화 해주고
        PocketBall.PocketMonster poketmon = ball.new PocketMonster(); // 외부클래스.내부클래스 형식으로 내부클래스를 초기화 하여 사용할 수도 있다
        poketmon.getPoketMember();
        
 // 위의 단계를 한줄로 표현
        PocketBall.PocketMonster poketmon2 = new PocketBall().new PocketMonster();
    }
}

 

# 스테틱 클래스(static class)

- static 클래스는 키워드가 붙은 내부 클래스(단, static 필드 변수나 static 메서드와 똑같지 않음)
- static 클래스 내부에는 instance 멤버와 static 멤버 모두 선언 가능

class PocketBall {
    int size = 100;
    static int price = 5000;

// static 내부 클래스
    static class PocketMonster {
        static String name = "이상해씨";
        int level = 10;

        public static void getPoketMember() {
// 외부 클래스 인스턴스 맴버 접근 불가능
		// System.out.println(size);
            
// 외부 클래스 스태틱 멤버 접근 가능
            System.out.println(price);
			
// 내부 클래스 멤버도 스태틱 맴버만 접근 가능
            System.out.println(name);
         // System.out.println(level);
        }
    }
}
public class Main {
    public static void main(String[] args) {
// 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
        PocketBall.PocketMonster poketmon = new PocketBall.PocketMonster();
        System.out.println(poketmon.level);
        System.out.println(PocketBall.PocketMonster.name);

// 클래스.정적내부클래스.정적메소드()
        PocketBall.PocketMonster.getPoketMember();
    }
}

(참고)
static classs가 메모리에 하나만 올라갈 수 있지 않음. (static class는 static 멤버와 다름)
내부 인스턴스 클래스처럼, 외부 인스턴스를 먼저 선언하고 초기화 하는 선수작업 불필요(내부 클래스의 인스턴스를 바로 생성할 수 있는 차이점)

public class Main {
// 스태틱 필드 변수
    static Integer num = new Integer(0);

// 내부 인스턴스 클래스
    class InnerClass{
    }

// 내부 스태틱 클래스
    static class InnerStaticClass{
    }
    
    public static void main(String[] args) {

// 스태틱 필드 변수는 유일해서 서로 같다
        Integer num1 = Main.num;
        Integer num2 = Main.num;
        System.out.println(num1 == num2); // true


// 생성된 내부 클래스 인스턴스는 서로 다르다
        Main.InnerClass inner1 = new Main().new InnerClass();
        Main.InnerClass inner2 = new Main().new InnerClass();
        System.out.println(inner1 == inner2); // false


// 생성된 내부 스태틱 클래스 인스턴스는 서로 다르다
        Main.InnerStaticClass static1 = new InnerStaticClass();
        Main.InnerStaticClass static2 = new InnerStaticClass();
        System.out.println(static1 == static2); // false
    }
}

 

# 로컬 클래스

- 메소드 내부에 위치하는 클래스(지역변수 같음)
- 지역변수 처럼, 해당 메서드 내부에서만 한정적 사용(해당 메소드 외엔 클래스 접근 불가)
- 접근제어자인 static 붙일 수 없음
- 인스턴스 생성 후 종료되고, 메모리(heap)영역에도 지워짐.

class PocketBall {
    int size = 100;
    int price = 5000;

    public void pocketMethod() {
        int exp = 5000;
        
 // 메소드 내에서 클래스를 선언
        class PocketMonster {
            String name = "이상해씨";
            int level = 10;

            public void getPoketLevel() {
                System.out.println(level); 		// 인스턴스 변수 출력
                System.out.println(exp); 		// 메소드 지역 상수 출력
            }
        }
		
 // 메소드 내에서 클래스를 선언
        class PocketMonster2 {
            String name = "리자몽";
            int level = 50;
        }

        new PocketMonster().getPoketLevel();
        System.out.println("메소드 실행 완료");
    }
}

 

# 익명 클래스

- 클래스 이름이 존재하지 않음(익명의 함수형태)
- 일회용 클래스
- 클래스 선언과 동시에 객체를 생성
- 생성자 존재하지 않음
- 일회용으로 클래스 내부구성을 선언해 필요한 메서드를 재정의 하여 사용하는 기법

public class Main {
    public static void main(String[] args) {
// Object 클래스를 일회성으로 익명 클래스로 선언하여 변수 o 에 저장
        Object o = new Object() {
            @Override
            public String toString() {
                return "내 마음대로 toString 바꿔보리기 ~";
            }
        };
		
// 익명 클래스의 객체의 오버라이딩한 메서드를 사용
        String txt = o.toString();
        System.out.println(txt); // 내 마음대로 toString 바꿔보리기 ~
    }
}

 

# 동일한 메서드 사용 시, 외부클래스 메서드 호출형태

// 외부 클래스
public class Main {

    public print(String txt) {
        System.out.println(txt);
    }

// 내부 클래스
    class Sub {
        public print() {         
        }
    }
}
public class Main {

    public void print(String txt) {
        System.out.println(txt);
    }

    class Sub {
        public void print() {
            Main.this.print("외부 클래스 메소드 호출");
            System.out.println("내부 클래스 메소드 호출");
        }
    }
}
public static void main(String[] args) {
    Main.Sub s = new Main().new Sub();
    s.print();
    /*      
    외부 클래스 메소드 호출
    내부 클래스 메소드 호출
    */
}

 

(연습1) 주소 호출

package nested;

public class ContectInfo {
	String address, phoneNo;
	
	public ContectInfo(String address, String phoneNo) {
		this.address = address;
		this.phoneNo = phoneNo;
	}
}
package nested;
import java.util.HashMap;

public class ContectInfoTest {
	public static void main(String[] args) {
		HashMap<String, ContectInfo> hashtable = new HashMap<String, ContectInfo>();    //HashMap 호출형태(제네릭 형태)
		hashtable.put("홍동우", new ContectInfo("서울시 구로구","010-1111-1111"));  			//입력방법
		hashtable.put("Aiden", new ContectInfo("서울시 강남구","010-2222-2222"));			//입력방법
		hashtable.put("aiden", new ContectInfo("서울시 강동구","010-333-3333"));			//입력방법
		
		ContectInfo obj = hashtable.get("Aiden");
		System.out.println("Aiden의 연락처");
		System.out.println("주소 및 연락처: " + obj.address+obj.phoneNo);
	});
	}
}
package nested;
import java.util.HashMap;

public class ContectInfoTest {

// 연락처 클래스
	public static void main(String[] args) {
  
		class ContectInfo {  		     //로컬이너 클래스: main 내에서만 사용되는 클래스(다른 명령보다 가장먼저 사용)
			String address, phoneNo;

			public ContectInfo(String address, String phoneNo) {
				this.address = address;
				this.phoneNo = phoneNo;
			}
			HashMap<String, ContectInfo> hashtable = new HashMap<String, ContectInfo>();    //HashMap 호출형태(제네릭 형태)
			hashtable.put("홍동우", new ContectInfo("서울시 구로구","010-1111-1111"));  			//입력방법
			hashtable.put("Aiden", new ContectInfo("서울시 강남구","010-2222-2222"));			//입력방법
			hashtable.put("aiden", new ContectInfo("서울시 강동구","010-333-3333"));			//입력방법

			ContectInfo obj = hashtable.get("Aiden");
			System.out.println("Aiden 연락처");
			System.out.println("주소: " + obj.address + obj.phoneNo);
		}
	}
}

결과

Aiden의 연락처
주소: 서울시 강동구 010-333-3333

 

(연습2) 이름없는 클래스로 출력해보기

package nested;
abstract public class MessageSender {    

	abstract void sendMessage(String message); 
}
package nested;

public class AnonymousClassEx2 {
	public static void main(String[] args) {
		Player obj = new Player() {					//이너클래스 바디선언
			
		@Override
		public void stop() {					//이름없는 클래스 오버라이딩
			System.out.println("플레이 종료!!");
		}
			
		@Override
		public void play(String source) {		//이름없는 클래스 오버라이딩
			System.out.println("플레이 시작: " + source);
		}
		};			// };로 이너클래스 바디 마감.

		obj.play("한남자 mp3");
		obj.stop();
	}
}

출력

플레이 시작: 한남자 mp3
플레이 종료!!

 

(연습3) 이너 클래스로 장바구니 구현

package nested;
import java.util.ArrayList;

//장바구니 클래스
public class Cart {
	ArrayList<Item> list = new ArrayList<Cart.Item>();
	
//장바구니에 상품추가 메소드
	void addItem(String name, int num, int unitprice) {
		list.add(new Item(name,num,unitprice));
	}

//장바구니에 상품삭제 메소드
	void removeItem(int index) {
		list.remove(index);
	}
//상품들의 객수
	int getItemNum() {
		return list.size();
	}

//장바구니 하나의 상품 가져오기
	Item getItem(int index) {
	return list.get(index);
	}
	
//장바구니 전체 총금액 구하기
	int getTotalPrice() {
		int total = 0;
		for(Item item : list) {
			total += item.getPirce();
		}
		return total;
	}
//장바구니 종류수량(갯수) 변경하기(index, num)형태
	void changeItemNumber(int index, int num) {
	Item item = list.get(index);
	item.num =num;
	}

//장바구니에 담길 상품 클래스
	class Item	{
		String name;
		int num;
		int unitPrice;
		public Item(String name, int num, int unitPrice) {
			this.name=name;
			this.num=num;
			this.unitPrice=unitPrice;
		}
//상품당 금액
		int getPirce() {
			return unitPrice *num;
		}
	}
}
package nested;
public class CartTest {
public static void main(String args[]) {
        Cart cart = new Cart();
        cart.addItem("쵸콜렛", 3, 1000);
        cart.addItem("케이크", 1, 25000);
        cart.addItem("샴페인", 1, 7000);
       Cart.Item item = cart.new Item("꽃다발", 1, 5000);
        cart.list.add(item);
        printCart(cart);
    }
//장바구니 정보출력
    static void printCart(Cart cart) {      
        int num = cart.getItemNum();
        System.out.println("      상품명   수량   단가    금액");        
        System.out.println("----------------------------------");        
        for (int cnt = 0; cnt < num; cnt++) {   		// 장바구니의 상품 목록을 순서대로 가져와서 출력!!
            Cart.Item item = cart.getItem(cnt);
            System.out.printf("%3d %5s %5d %7d %7d %n", cnt+1, item.name, item.num, item.unitPrice, item.unitPrice);
        }       
        System.out.println("----------------------------------");        
        System.out.printf("      총계              %10d %n", cart.getTotalPrice());
    }
}
      상품명   수량   단가    금액
----------------------------------
  1   쵸콜렛     3    1000    1000 
  2   케이크     1   25000   25000 
  3   샴페인     1    7000    7000 
  4   꽃다발     1    5000    5000 
----------------------------------
      총계                   40000


## 스레드 Thread   <<  멀티 테스킹 multi tasking << 하이퍼스레딩 Hyper Threading : 처리속도(<<)

- 정의: 프로세스 내의 독립적 실행단위(프로세스: 실행중인 프로그램)
            프로세스끼리 다른 프로세스의 메모리엔 접근 불가(이유: 스레드로 구분해 자원공유 목적. 중복 최소화 CPU 성능향상 목적)
- 목적: 다중작업 필요한 경우, 스레드를 이용하는것이 훨씬 효율적임.
- 문법: 4종류(주로사용)
          Runable --> 인터페이스 구현 함수
          Thread --> 클래스 상속 구현 함수
          run() --> 메소드 오버라이딩 호출함수
          start() --> 메소드 호출함수

- 동시성 필요이유
1) 하드웨어적 한계: CPU발열
2) 논리적인 효율: 작업을 번갈아가면서 처리하는 형태

# 스레드 상태

스레드 상태 설명
New 스레드가 생성되고 아직 호출되지 않은 상태
Runnable 스레드가 실행되기 위해 기다리는 상태
CPU를 할당 받을 수 있는 상태(실행될 준비가 됨)
Blocked 스레드가 특정 이벤트(입출력 요청 등) 발생을 대기하는 상태
CPU를 할당 받지 못함. Runnable 상태로 전환되기 전까지 대기
Terminated 스레드가 실행을 완료하고 종료된 상태
더 이상 실행될 수 없음, 메모리에서 제거됨

 

# 뮤텍스(mutex)

- 임계 구역에 1개의 스레드만 들어갈 수 있는 동기화 기법

# 세마포어(semaphore)

-임계구역에 여러 스레드가 들어갈 수 있고 counter를 둬서 허용가능한 스레드를 제한하는 기법

(연습1) 레드 구현해보기

package thread;

public class TreadEx1_1 extends Thread {
	public void run() {
		for(int i=0; i<5; i++){
			System.out.println(getName());
		}
	}
}
package thread;

public class ThreadEx1_2 implements Runnable  {		// Runnable은 스레드의 인터페이스 함수

	public void run() {			//멀티스레드 구현하기 위해 run()을 사용해야 됨.
		for(int i=0; i<5; i++) {
			System.out.println(Thread.currentThread().getName());
		}
	}
}
package thread;

public class TheradEx1Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreadEx1_1 t1 =new TreadEx1_1();
		
		Runnable r = new ThreadEx1_2();
		Thread t2 = new Thread(r);
		
		t1.start();
		t2.start();
	}
}

결과값

Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-1
Thread-1
Thread-1
Thread-1
Thread-1

 

# 멀티 스레드 multi thread

- 하나의 프로세스 내의 여러개의 스레그가 실행되는 흐름 같은 것(은행 예약계좌 이체 형태)
- 두 가지 이상의 동작을 동시처리 가능.
- 하나의 스레드가 지연되어도 다른 스레드가 작업을 지속할 수 있음
- 예) 웹 브라우저의 단일탭/창내의 브라우저 이벤트 루프,네트워크처리, I/O 및 기타 작업을 관리하고 처리하는데 사용됨.

- 장점

1) 프로세스보다 가벼움
2) 효율성
3) 응용시간 단축(멀티 프로세스보다 빠른 응답)
4) 자원공유가 용이함
5) 컨텍스트 스위칭 오버헤드가 작음

- 단점

1) 안정성(각각의 프로세스가 독립적으로 동작, 서로 영향을 받지 않으므로 계속 동작할 위험성)
      --> 해결: 예외처리(exception)
2) 동기화로 인한 성능저하 --> 스레드간 동기화 접근을 제어하기 위한 필수기술
3) 병목현상이 발생되어 성능이 저하됨
4) 데드락(교착상태)

(연습) 멀티 스레드1

package thread;

public class ThreadEx2_1 {
	public void run() {
		for(int i=10; i>0; i--);
		System.out.println(Thread.currentThread().getName());
	}
}
package thread;

import javax.swing.JOptionPane;

public class ThreadEx2Test {
	public static void main(String[] args) {
		String input =JOptionPane.showInputDialog("아무 값이나 입력하시오.");
		System.out.println("입력한 값은" + input + "입니다.");

		for(int i=10; i>0; i--) {
			System.out.println(i);
			try {
				Thread.sleep(1000);  		//10초임
			} catch(Exception e) {
			}
		}
	}
}

(결과)

입력한 값은50입니다.
10
9
8
7
6
5
4
3
2
1

 

(연습2) 멀티스레드2

package thread;

public class ThreadEx2_1 extends Thread {

	public void run() {

		for(int i=10; i>0; i--) {
			System.out.println(i);
			try {
				Thread.sleep(1000);  		//10초임
			} catch(Exception e) {
			}
		}
}
}
package thread;

import javax.swing.JOptionPane;

public class ThreadEx2Test {
	public static void main(String[] args) {

		ThreadEx2_1 t = new ThreadEx2_1();
		t.start();

		String input =JOptionPane.showInputDialog("아무 값이나 입력하시오.");
		System.out.println("입력한 값은" + input + "입니다.");


		//		for(int i=10; i>0; i--) {
		//			System.out.println(i);
		//			try {
		//				Thread.sleep(1000);  		//10초임
		//			} catch(Exception e) {
	}
}
10
9
8
7
입력한 값은55입니다.
6
5
4
3
2
1

 

(연습4)  멀티 스레드3

package thread;
public class ThreadEx3_1 extends Thread{
	public void run() {
		for(int i=10; i<300; i--) {
			System.out.println(i);
			for(int x=0; x<10000000; x++);
		}
	System.out.println("<< t1종료>>");
	}
}
package thread;
public class ThreadEx3Test extends Thread{
	public static void main(String[] args) {
		ThreadEx3_1 t1 = new ThreadEx3_1();
		ThreadEx3_2 t2 = new ThreadEx3_2();
		t2.setPriority(7);		//1~10 우선순위(높은 수가 높은 우선순)
		System.out.println("t1 우선순위: " +t1.getPriority());
		System.out.println("t1 우선순위: " +t2.getPriority());
		t1.start();
		t2.start();

//순차적 실행방법(try catch문)
		t1.start();
		try {
			t1.join();		//두 스레드가 번갈아 실행하지 않고, 순차적 실행
		}catch(InterruptedException e) {
		}t2.start();

//초단위 실행방법(try catch문) sleep(초단위 1000 --> 1초)
        t1.start();
		t2.start();
		try {
			t1.sleep(5000);		//5초단위
		}catch(InterruptedException e) {
		}
		System.out.print("<< main 종료 >>");
	}
}

 

(연습5) 멀티 스레드(동기화)

package thread;
//계좌 객체
public class Account {
	int balance=1000;
	public void withdraw(int money) {
		if(balance >= money) {
			try {
				Thread.sleep(1000);

		}catch(Exception e) {
		}
		balance -= money;
	}//if-end
	}
}
package thread;

public class AccountThread implements Runnable {
	Account acc= new Account();

	public void run() {
		while(acc.balance>0){
			int money = (int)(Math.random()*3+1)*100;
			acc.withdraw(money);
			System.out.println("잔액: "+acc.balance);
		}
	}
}
package thread;

public class AccountTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	Runnable r = new AccountThread();	//하나의 Account객체
	Thread t1 = new Thread(r);
	Thread t2 = new Thread(r);
		t1.start();
		t2.start();

	}

}
잔액: 800
잔액: 800
잔액: 700
잔액: 500
잔액: 400
잔액: 300
잔액: 100
잔액: -200
잔액: -300


## 동기화 단점보완: 음수값이 나올수 없도록 처리.

- 한 스레드 실행중일때, 잠시 동기화 처리해야 됨.

- 해결방법(3가지)
1번째 방법: 동기화 처리가 필요한 메소드synchronized를 붙여줌.
2번째 방법: 동기화 처리가 필요한 라인synchronized(this){ 를 걸어줌
3번째 방법: finalReentrantLock으로 변수값인 key를 선언 後 key.lock(); 시작 --> key.unlock(); 마감 형태 --> key값에 따라 대기를 걸어두므로 성능엔 좋지 않음.
(예시)

package thread;
//계좌 객체

import java.util.concurrent.locks.ReentrantLock;

public class Account {
	int balance=1000;
	public final ReentrantLock key = new ReentrantLock(); //3번째 방법: ReentrantLock란 메소드를 final과 함께 사용해서 key란 변수에 담아서 new로 선언해두고
	
//1번째 방법: 동기화처리가 필요한 메소드에 synchronized를 붙여줌	(단점: 메소드 전체에 걸리므로 성능저하)
	public synchronized void withdraw(int money) {
//	public void withdraw(int money) {
		
		synchronized (this) {		//2번째 방법: 동기화가 필요한 라인에만 synchronized(this){ 를 걸어줌

			key.lock(); 	//3번째 방법의 key.lock();을 걸어두고
			if(balance >= money) {
				try {
					Thread.sleep(1000);
				}catch(Exception e) {
				}
				balance -= money;
			} //if-end
			key.unlock(); 	//3번째 방법의 key.unlock();으로 제어문 밖에서 풀어줌.
		}
	}
}

(3번째 방법 예시)
lock과 unlock 걸어서 아래 예시처럼 key값에 따라 대기하도록 걸어둘 수 있음(순차적 실행 형태임)

import java.util.concurrent.locks.ReentrantLock;
classs IHaveTwoNum {
	int num1=0;
	int num2=0;
		public void addOneNum1() {
		key1.lock();
		try	{
			num1+=1;
		}finally{
		key1.unlock();
		}
	}
    
	public void addTwoNum1() { 
		key1.lock();
		try	{
			num1+=2;
		} finally	{
		key1.unlock();
		}
	}	
	public void addOneNum2() { 
		key2.lock();
		try	{
			num2+=1;
		} finally {
		key2.unlock();
		}
	}
    
	public void addTwoNum2() { 
		key2.lock();
		try	{
			num2+=2;
		} finally {
		key2.unlock();
		}
	}
	
	public void showAllNums() {
		System.out.println("num1: "+num1);
		System.out.println("num2: "+num2);
	}
	private final ReentrantLock key1=new ReentrantLock();
	private final ReentrantLock key2=new ReentrantLock();
}

	class AccessThread extends Thread {
	IHaveTwoNum twoNumInst;
	public AccessThread(IHaveTwoNum inst) {
		twoNumInst=inst;
	}
	
	public void run() {
		twoNumInst.addOneNum1();
		twoNumInst.addTwoNum1();
		twoNumInst.addOneNum2();
		twoNumInst.addTwoNum2();
	}
}

class UseReentrantLock {
	public static void main(String[] args){
		IHaveTwoNum numInst=new IHaveTwoNum();
		
		AccessThread at1=new AccessThread(numInst);
		AccessThread at2=new AccessThread(numInst);
		at1.start();
		at2.start();
		try	{
			at1.join();
			at2.join();
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		numInst.showAllNums();
	}
}

 

## I/O 상속구조

- 입출력과 연관되어 있어 클래스명이 긴편(구조: 계층구조)
- try  catch문은 무조건 사용
- read로 읽고
- writer로 아웃시키는 형태
- 주로: 은행 입출금으로 연습

 

read 함수: int형만 받을 수 있음 --> data란 변수를 int로 선언 이유
write 함수: int형
만 읽을 수 있음 --> data란 변수를 char로 받을 수 있음 (int와 char 관계)

(연습6)

package io;

import java.io.FileInputStream;
import java.io.IOError;
import java.io.IOException;

public class FileViewer {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		FileInputStream fis = new FileInputStream(args[0]);
		
		int data = 0;				//아래의 read가 int만 잡을 수 있으므로 data는 int형임. char랑 혼용사용(정수형이므로)
		while((data=fis.read())!=-1) {		// read는 int만 받으므로 data란 변수를 int로 잡음. eof(End of File)를 표현하는 키워드
			char c = (char)data;		//아스키코드 65가 A이므로 char로 변환해서 볼기 위해 data를 char로 변환
			System.out.print(c);		//스페이스(32:아스키코드)이므로
		}
		
	}

}
package io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileInputStream;

public class FileCopy {
	public static void main(String[] args) throws IOException {
		try {
			FileInputStream fis = new FileInputStream(args[0]);
			FileOutputStream fos = new FileOutputStream(args[1]);
			int data = 0;					
			while((data=fis.read())!=-1) {	//read로 호출, read함수는 int만 받을 수 있고 char로 불러올 수 있음
				char c = (char)data;		
			fos.write((char)data);		//write로 호출, write함수는 int로 읽을 수 있고 char로도 받을 수 있음
			}			
			fis.close();
			fos.close();
		}catch(IOException e) {		
			e.printStackTrace();	//printStackTrace로 호출
		}
	}
}
728x90
반응형
LIST