thread 2개가
main thread 가 700쯤 가면 1000이 넘지 않도록, 다른 method가 (10초마다 300씩 차감) 700을 가져가서 400으로 제어함
package sampleproj;
// 이 thread의 instance를 생성해서 실행하면
// 10초마다 일정량의 메모리사용량을 감소시킴
class ThreadEx_11_1 extends Thread{
final static int MAX_MEMORY = 1000;
int usedMemory = 0;
@Override
public void run() {
while(true) { // 무한루프
try {
Thread.sleep(10000); //try~catch문 씌워주기
} catch (InterruptedException e) {
}
gc(); // 10초간 잤다 깨면서 메모리 청소 좀 해라 ~
System.out.println("남은 메모리량 : " + freeMemory());
}
}
public void gc() {
usedMemory -= 300; // usedMemory = usedMemory - 300;
if(usedMemory < 0) {
usedMemory = 0; //메모리값이 마이너스인 경우는 없으니까 0
}
}
public int totalMemory() {
return MAX_MEMORY;
}
public int freeMemory() { // 가용 메모리
return MAX_MEMORY - usedMemory;
}
}
public class ThreadEx_11 {
public static void main(String[] args) {
ThreadEx_11_1 t = new ThreadEx_11_1();
t.setDaemon(true);
t.start(); // start 하면 run이 실행됨
int requiredMemory = 0;
for(int i=0; i<20; i++) {
requiredMemory = ((int)(Math.random()*10)) * 20;
// Math.random 0<= 난수 < 1 사이의 난수값을 도출
// 0 ~ 10 인데, 정수화 시켜서 소수점이 날라가서 0 ~ 9까지의 난수값
// 0 ~180 , 0, 20, 40, 60, ... 180
// 위에서 구한 필요한 메모리량이 사용할 수 있는 메모리 량보다 크거나
// 혹은 전체 메모리의 60% 이상을 사용했을 때 GC를 깨울 거에요
if((t.freeMemory() < requiredMemory) ||
t.freeMemory() < t.totalMemory() * 0.4) {
t.interrupt(); // 자고 있던 memory를 깨움
}
t.usedMemory += requiredMemory; // 사용된 메모리량을 누적시킴
System.out.println("남은 메모리량 : " + t.freeMemory());
}
}
}
로직 상으로는 마이너스가 나올 수 없는데 ,,어디선가 허점이 있다
=> 메모리 청소하면서도 main이계속 돌고있어서 그럼
메모리 청소할 때 main method를 잠시 멈추고, 청소 후 다시 main method가 실행해야함 (순차처리가 필요)
=> 이때 join이 필요
if((t.freeMemory() < requiredMemory) ||
t.freeMemory() < t.totalMemory() * 0.4) {
t.interrupt(); // 자고 있던 memory를 깨움
try {
t.join(100); // 0.1초동안 sleep에서 깨어나서 메모리를 청소함.
//인자없이 사용하면 무한루프에 빠지기 때문에 숫자를 넣어줌
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t.usedMemory += requiredMemory; // 사용된 메모리량을 누적시킴
System.out.println("남은 메모리량 : " + t.freeMemory());
}
이런 현상이 발생하지 않도록 하나의 Thread가 특정 작업을 마치기 전까지 다른 Thread에 의해서 방해 받지 않도록 처리해야 함 : 동기화
① Critical Section(임계영역)
② Lock (락, 잠금)
: monitor라고 하기도 함
: class를 정의
: 여기에 예금잔액 데이터가 있음
:
--사진 넣기
package sampleproj;
class Account {
//생성자
public Account() {
}
public Account(int balance) {
super();
this.balance = balance;
}
// field
private int balance;
//business method
public void withdraw(int money) {
if(balance >= money) {
try {
Thread.sleep(1000); //현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
class ThreadEx_12_1 implements Runnable {
//field
Account acc = new Account(1000);
@Override
public void run() {
while(acc.getBalance() > 0 ) {
int money = (int)(Math.random() * 3 + 1) * 100;
// 0 ~ 3인데 +1 해서 1 ~ 4
acc.withdraw(money); //공용객체의 출금처리
System.out.println("남은 금액 : " + acc.getBalance());
}
}
}
public class ThreadEx_12 {
public static void main(String[] args) {
ThreadEx_12_1 r = new ThreadEx_12_1();
Thread t1= new Thread(r);
t1.start();
}
}
Thread 2개 동시 진행
public class ThreadEx_12 {
public static void main(String[] args) {
ThreadEx_12_1 r = new ThreadEx_12_1();
Thread t1= new Thread(r);
Thread t2= new Thread(r);
t1.start();
t2.start();
}
}
=> 문제 발생. 마이너스 나옴
thread 1이 자는 동안 thread 2가 200차감함
-> thread 1이 깨어나서 또 200차감
-> 남은 잔액이 -100가 됨
해결하기 위해 !
Synchronized keyword를 이용 : Lock, Monitor를 획득할 수 있음
① method 앞에 붙여서 동기화 method를 만든다
: method를 호출하면
// business method
// synchronized method (동기화 메소드)
// 이 메소드를 실행한 Thread가 먼저 Lock(Monitor) 획득.
// 하나의 thread가 메소드를 호출하면 나머지 하나는 block됨 !
public synchronized void withdraw(int money) {
// balance => 300
// thread 1 => 200 차감
// thread 2 => 200 차감
if(balance >= money) {
try {
Thread.sleep(1000); //현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}
}
②
public void withdraw(int money) {
// ~~~
// 여기 코드는 동기화 안 됨
// ~~~
synchronized(this) {
if(balance >= money) {
try {
Thread.sleep(1000); //현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
} catch (Exception e) {
// TODO: handle exception
}
balance -= money;
}
}
// ~~~
// 여기 코드는 동기화 안 됨
// ~~~
}
임계영역 code가 다 실행되어야 다른 Thread가 실행될 수 있다
=> 너무 오래 걸림 : 다른 Thread가 오래 기다려야 함
1초마다 자신의 이름을 출력하는 Thread를 2개 생성한다
하지만, 두개의 thread의 실행 순서는 알 수가 없다
우리가 만들고 싶은 건 : 두개의 thread가 번갈아 가면서 자신의이름을 출력하는 코드를 구현
=> wait(), notify() 이용하기
wait- Synchronized 일어남
https://scshim.tistory.com/243 내가 찾은 참고자료
Thread의 이름은 따로 field 잡을 필요 없음
공용객체,
package sampleproj;
// 1. 공유객체를 생성하기 위한 class
class Shared {
// 공유객체의 공유 메소드
public synchronized void printName() { // 2. // 11.동기화
try { // 3.
for(int i=0; i<10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
notify(); // 13. 여기에 위치해야 함
wait(); // 12.첫번째thread를 재우고 두번째thread 실행->wait
//notify(); 를 여기다 쓰면 실행이 안 됨. 이미 들어가있는 애를 끄집어 내고 다시 실행 시켜줘야함
}
} catch (Exception e) {
}
}
}
class ThreadEx_13_1 implements Runnable{ // 4.
public ThreadEx_13_1(Shared shared) {// 6.
super();
this.shared = shared;
}
private Shared shared; // 5.
@Override // 7. 본인이 가진 공유객체의 공유 method를 가져옴. printName
public void run() {
shared.printName();
}
}
public class ThreadEx_13 {
public static void main(String[] args) {
// 8. 공유객체 만들기
Shared shared = new Shared(); // 9.공유객체를 가지고
Thread t1 = new Thread(new ThreadEx_13_1(shared),"첫번째 쓰레드"); // 10.runnable객체를 만들고 -> thread 만들고 -> run 호출 -> 공유객체에 대해서 printName
Thread t2 = new Thread(new ThreadEx_13_1(shared),"두번째 쓰레드");
t1.start();
t2.start();
}
}
: Java Input/Output
: Java 입출력에 관련된 내용
Java.io package로 제공(class가 제공)
Stream
: 데이터 전송 통로, instance로 존재(class가 제공)
확장된 것 => Java NIO
Java에서 program -> File에 데이터를 저장
① Stream은 2가지 종류가 있음
: 입력 Stream / 출력 Stream 이 따로 존재함
: 단방향 스트림
② Stream은 FIFO구조(First in First out) 선입선출 구조
Stream을 통해 A-B-C-D
--사진
③ Stream을 결합
해서 사용할 수 있음
Stream : 전체 Stream을 지칭 (Input/Output)
--사진
④ Stream은 byte단위(숫자)의 Stream과 문자 단위(Reader,Writer)의 Stream으로 구분됨
기본 Stream은 사용하기 불편함!
특히 문자열 기반의 입출력은 많이하는데, 기본 Stream으로는 너무 힘들다
inputStream 겉에 inputStream Reader => Stream 결합
기본적으로 우리에게 제공된 Stream.
system.out -> Output Stream의 객체
system.in -> InputStream의 객체
JavaIO 연습 프로젝트 생성
package sample;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Exam01_KeyboardInput {
public static void main(String[] args) {
System.out.println("키보드로 한 줄을 입력하세요!");
// 키보드로부터 입력을 받으려면, 데이터 연결통로(Stream)이 있어야 함
// System.in이 제공되는데.. InputStream class의 객체 => 사용하기 너무 불편 !
// 문자기반의 데이터를 받기를 원함 => Reader를 하나 만들어야 함
// new InputStreamReader(System.in) 이렇게 Stream을 결합해서
// 조금 더 편한 문자 기반의 통로를 열었음 그럼에도 불구하고 불편함 !
// 조금 더 편한 문자 기반의 데이터 입력 연결통로를 만들어 볼 거에요
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
String s = br.readLine();
System.out.println("입력받은 데이터는 : " + s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
결국 Stream이 데이터 연결 통로
출력
: BufferedReader
이용
출력
System.out
제공된 Stream 이용PrintWriter
이용예를 들어) HashMap을 File에 저장 !
=> Stream을 통해 객체를 읽어오고/내보내려면 어떻게 해야하나요?
package sample;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
public class Exam02_ObjectStream {
public static void main(String[] args) {
// 먼저 Stream을 통해 내보낼 HashMap을 간단히 만들어보자
HashMap<String, String> map = new HashMap<String, String>();
map.put("1", "홍길동");
map.put("2", "신사임당");
map.put("3", "강감찬");
// 실제 파일을 생성하려면 당연히 자바쪽에서 File객체를 만들어야 함
File file = new File("readme.txt");
try {
FileOutputStream fis = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fis);
oos.writeObject(map);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
: 물리적인 프레임워크
computer라는 물리적인 장치
실행적인 program이
② Internet을 이용
: 물리적인 network 위에서 수행되고 있는 program을 이용 => Service
③ Internet에 연결되어 있는 각 computer(안의 여러개의 process가 다른 process와)가 data 통신을 하려면 주소
가 필요함
IPv4
④ DNS(Domain Name System)
: IP 주소는 숫자라서 기억하기 힘들기 때문에 이를 문자로 표현하기로 함
ex) www.naver.com
⑤ Protocol
: 국가 간의 조약
⑥ Socket
: 결국 너무 복잡하고 어려워서 socket
이라는 개념이 나옴
chatting이 제대로 돌기 위해서는 (Thread -> 동기화 -> 공유객체)