관리 메뉴

개발 노트

8/1 Properties, ArrayList와 List, 프로세스, 프로세서, 스레드, 스레드의 생명주기, 멀티태스킹, 스케줄링, thread 클래스(Runnable), 멀티스레드, 싱글스레드, sleep, synchronized(동기화), Lambda 본문

프로젝트 기반 JAVA 응용 SW개발 : 22.07.19~23.01.20/JAVA

8/1 Properties, ArrayList와 List, 프로세스, 프로세서, 스레드, 스레드의 생명주기, 멀티태스킹, 스케줄링, thread 클래스(Runnable), 멀티스레드, 싱글스레드, sleep, synchronized(동기화), Lambda

hayoung.dev 2022. 8. 1. 20:27

database.properties

driver=oracle.jbdc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:orcl
username=scott
password=tiger

 

PropertiesEx.java

package ch11;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Properties;

public class PropertiesEx {

	public static void main(String[] args) throws FileNotFoundException, IOException {
		Properties pt = new Properties();
		//database.properties의 리소스를 얻어서 path를 보여줘라
		//이 출력결과에서 %20은 ascii코드에서 헥사코드 space임.
		String path = PropertiesEx.class.getResource("database.properties").getPath();
		System.out.println("1 path : " + path);
		
		//utf-8로 디코딩하면 %20이 띄어쓰기가 되어있는 것을 볼 수 있음.
		path = URLDecoder.decode(path,"utf-8");
		System.out.println("2. path : " + path);
		
		pt.load(new FileReader(path));	//파일을 읽어들인다.
		//파일이 없을수도 있으므로 예외처리
		String driver = pt.getProperty("driver"); 	//.getProperty는 키를 사용하여 속성 검색
		System.out.println("드라이버 : " + driver);
		// =  기준으로 앞에 있는 것은 key, 뒤에 있는 것은 value이다.
		//예를들어 database.properties에서 driver=oracle.jbdc.OracleDriver가
		//driver는 key, oracle.jbdc.OracleDriver는 value라는 뜻.
		
		String url = pt.getProperty("url");
		System.out.println("3. url : " + url);
		
		//과제
		String username = pt.getProperty("username");
		System.out.println("4. username : " + username);
		
		String password = pt.getProperty("password");
		System.out.println("5. password : " + password);

	}

}

출력 결과 

 

 

p.18 컬렉션-List (ArrayList) 단점

배열은 구조가 간단하고 데이터를 읽어오는 데 걸리는 시간(접근시간, access time) 이 가장 빠르다는 장점이 있지만 단점도 있다.

단점 1 : 크기를 변경할 수 없다.

- 크기를 변경해야 하는 경우 새로운 배열을 생성하고 데이터를 복사해야 한다. (비용이 큰 작업)

- 크기 변경을 피하기 위해 충분히 큰 배열을 생성하면, 메모리 낭비가 심해진다.

단점 2 : 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다.

- 데이터를 추가하거나 삭제하기 위해, 많은 데이터를 옮겨야 한다

- 그러나, 순차적인 데이터 추가(마지막에 추가)와 순차적으로 데이터를 삭제하는 것 (마지막에서부터 삭제)은 빠르다.

 

면접에서 자주 물어보는 질문(중요) : 배열과 list  / list와 set / list와 map 의 차이점.

 

 

ArrayListEx.java : 과제

package ch11;

import java.util.ArrayList;

public class ArrayListEx {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		list.add("Java");
		list.add("JDBC");
		list.add("Servlet/JSP");
		list.add(2, "Database");
		list.add("iBATIS");
	
		//과제
		System.out.println("1. 총 객체 수 : " + list.size());
		System.out.println("2. 인덱스 기준으로 두 번째 항목 조회 : " + list.get(2));
		System.out.println("3. 전체 리스트 조회 : ");
		for(String str : list) {
			System.out.println(list.indexOf(str) + ") " + str + "\t");
		}
		
		System.out.println();
		
		//정답코드
		int size = list.size();
		System.out.println("1. 총 객체수 : " + size);
		
		String skill = list.get(2);
		System.out.println("2. : " + skill);
		for(int i = 0; i<list.size(); i++) {
			String str = list.get(i);
			System.out.println(i +") " + str);
		}
		
		
       // 2. HomeWork 
      //  1) 총 객체수: 5
      //  2) 인덱스 기준으로 2번째 항목 조회(Index)
      //  3) 전체 리스트 조회
		//출력 결과
		//1.  총 객체수: 5
		
		//2: Database
		
		//0:Java
		//1:JDBC
		//2:Database
		//3:Servlet/JSP
		//4:iBATIS
	}

}

출력 결과

 

[12. 스레드]

1. 프로세스(Process) : Program이 Memory를 획득하고 PID를 가진 상태.

2. Multi-Process :  동시에 여러개의 Process가 수행되는 것. 프로그램이 동시에 같이 돌아가는 것. CPU가 시간 단위로 선점하게 해 줌.

3. 프로세서(Processor) : CPU

4. Multi-Processer : 하나의 프로그램 이상을 여러개의 CPU를 동시에 수행

5. Thread : Program이 수행될 수 있는 최소한의 단위

6. Multi-Thread :  여러 Thread가 동시에 수행

 

*프로세서와 프로세스 헷갈릴 수 있음 주의.

 

프로세서

p.3 프로세스와 쓰레드(process & thread) 

스레드란 하나의 프로그램이 하나이상의 독립적 서브 Task로 분리되어 실행될때 각 서브 Task 를 Thread라고 한다.

- 각 스레드는 별개로 실행하면서 CPU를 공동으로 사용

- 경량(lightweight) 프로세스

- 다중 스레드 : 하나의 프로세스에서는 동시에 여러 쓰레드가 실행. 하나의 새로운 프로세스를 생성하는 것보다 하나의 새로운 쓰레드를 생성하는 것이 더 적은 비용이 든다

프로세스란 실행 중인 프로그램. 자원(resources)과 쓰레드로 구성

 

p.4 Thread의 생명주기 (면접에 나올 수 있음, 중요)

start는 메모리로 올리는 것

ready : 메모리에 올라가 있는 것

running : CPU에 할당돼있는 상태

cpu를 할당받다가 대기상태로 빠지게 되면 sleep, wait

running 수행 완료가 되면 terminated로 이동

notify, notifyAll, resume : 다시 메모리로 올라가 있는 상태가 되는 것.

 

p.5 멀티쓰레드의 장단점

- 멀티 쓰레드는 프로세스를 복사하는것이 아니라 Function 단위로 실행시키는 것이다.

- 즉 어떤 Function에서 다른 Function을 호출하면서 그 밑의 루틴을 다시 실행하는 것이다.

- 이것은 같은 프로세스이므로 멀티 프로세스에 비해서 부하를 덜준다.

- 그래서 경량프로세스란 말을 하는 것이다.

장점

1) 자원을 보다 효율적으로 사용할 수 있다.

2) 사용자에 대한 응답성(resposeness)이 향상된다.

3) 작업이 분리되어 코드가 간결해진다.

단점

1) 동기화(synchronization)에 주의해야 한다.

2) 교착상태(dead-lock)가 발생하지 않도록 주의해야 한다.

3) 각 쓰레드가 효율적으로 고르게 실행될 수 있게 해야 한다.

 

p.6 멀티태스킹(Multi-Tasking)

멀티 태스킹

- 컴퓨터에서 각각의 일을 전담하는 해당 프로그램들(여러 개의 프로세스 (Process))이 동시에 실행되는 것.

- 멀티 태스킹을 위해 운영체제가 취하는 방식이 멀티 프로세스 시스템.

스케줄링(Scheduling)

- 멀티프로세스 시스템에서 각 프로세스는 동시에 실행되는것 처럼 보이지만, CPU가 하나이기 때문에 실행시간을 잘게 나누어 프로세스가 돌아가는데 각 프로세스들이 돌아가면서 CPU를 점유하는데 프로세스간 CPU점유작업을 말함. 시간을 할당하는 것임.

 

p.7 Thread 클래스

- JDK는 스레드를 지원하는 java.lang.Thread 클래스 제공

- 스레드를 생성하기 위해 사용

-4개의 생성자를 제공

- Thread() : 클래스, 스레드명을 만들지 않는 것

- Thread(String s) : 클래스. 스레드명을 만드는 것

- Thread(Runnable r) : 인터페이스 상속받음

- Thread(Runnable r, String s) : 인터페이스 상속받음

 

Runnable이 있는 이유, 4개의 생성자씩이나 제공하는 이유(면접에 가끔 나옴, 중요) : 

어떤 클래스를 스레드로 쓰려고 하는데 이미 상속받은 경우, 클래스는 단일상속만 가능하기 때문에 스레드를 상속받을 수 없다. 이러한 다중상속이 불가능한 점을 해결하기 위해 인터페이스는 다중상속이 가능하기 때문에 인터페이스를 이용해 스레드를 구현하는 방법을 만들어놓은 것이다.

 

p.8 Thread 클래스의 메서드

 

 

 

 

 

 

p.9 스레드의 생성 및 이용

스레드를 생성하는 2가지 방법

1. Thread 클래스를 상속받은 뒤 run 메소드를 overriding하여 스레드가 실행할 코드를 작성한다.

public class WorkerThread extends Thread {
	@Override
    public void run() {
    //스레드가 실행할 코드
    }
}
Thread thread = new WorkerThread();

2. Runnable 인터페이스를 사용하는 방법 (현재의 클래스가 이미 다른 클래스로부터 상속 받고 있는 경우)

Runnable은 작업스레드가 실행할 수 있는 코드를 가지고 있는 객체이다. 이것은 인터페이스 타입이기 때문에 구현 객체를 만들어 대입해야 한다. Runnable에는 run() 메소드가 정의되어 있는데, 구현 클래스에 run()을 재정의해서 작업 스레드가 실행할 코드를 작성한다.

class Task implements Runnable {
	public void run() {
    스레드가 실행할 코드;
    }
}

Runnable은 작업 내용을 가지고 있는 객체이지 실제 스레드는 아니다. Runnable 구현 객체를 생성한 후 이것을 매개값으로 해서 Thread 생성자를 호출하면 비로소 작업 스레드가 생성된다.

Runnable task = new Task();

Thread th1 = new Thread(task);

 

 

[ch12]

 

Threadtest1.java

package ch12;

class ThreadExample1 extends Thread {	//Thread를 상속받아서 만듦
	public ThreadExample1(String str) {
		super(str); 	//생성자는 부모에게 위탁
	}
	
	//cpu에게 할당하는 run
    //스레드가 cpu를 할당받는 순간에 run 안에 있는 것이 실행되는 것임.
	@Override
		public void run() {
			//super.run(); 	//부모 없앰.
		for (int i = 1; i<=100; i++) {
			System.out.print(getName() + i + " \t");	//getname()은 스레드의 이름을 가져오는 것
			if (i%10==0) System.out.println();
			try {
				//thread.sleep : 너무 빠르므로 눈으로 인식할 수 있도록 1000분의 50초를 쥐어준다.
				Thread.sleep(50); 	//1000milliseconds = 1초
			} catch (InterruptedException e) {				
			}
		}
		super.run();
	}
	
}

public class Threadtest1 {

	public static void main(String[] args) {
		ThreadExample1 a1 = new ThreadExample1("subThreadA");
		ThreadExample1 a2 = new ThreadExample1("subThreadB");
		
		//start()를 하게 되면 메모리에 올라가고 위의 run()때문에 CPU를 받아서 실행됨.
		//A와 B와 main이 번갈아 돌아감. 순서는 보장할 수 없음. a스레드, b스레드, main스레드가 각각 돌아가는 것임.
		//각각 3개의 스레드가 돌아갈 때 c분할(타임셰어링)으로 각각 돌아가게 됨
		//cpu가 알아서 할당하는 것이기 때문에 개발자가 관여할 수 없음. 이것이 멀티스레드임.
		//cpu가 시간을 적당하게 각 프로세스에게 할당해주는 것. 
		a1.start(); 	
		a2.start();
		for(int i = 1; i<=100; i++) {
			System.out.print("Main " + i + "\t");
			if (i%10==0) System.out.println();
		}
		//이렇게 돌리면 cpu를 할당받는 것이 아닌 메인스레드에서 내가 직접 돌려주었기 때문에
		//(start를 하지 않고 run을 하였기 때문에)
		//멀티스레드가 아니고 싱글스레드이다.
		a1.run();
		a2.run();
	}
}

출력결과 1)

a1.start(); 

a2.start();

for문

을 돌렸을 때

: 멀티스레드이다. 각각 돌아간다.

 

출력결과 2)

a1.run();
a2.run();
을 돌렸을 때

: 싱글 스레드이다. a1.run이 끝나야 a2.run이 돌아간다.

 

 

Threadtest3.java

cpu는 똑같이 할당해주지만 sleep을 통해 개발자가 조정이 가능하다.

package ch12;

class ThreadExample2 extends Thread {
	@Override
	public void run() {
		for (int i = 1; i<=20; i++) {
			System.out.print("대박" + i + "\t"); //무슨 스레드인지 표시해두는 것이 편함.
			if(i%5==0) System.out.println();
			try {
				sleep(50);
			} catch (InterruptedException e) {
			}
		}
	}
}

class ThreadExample3 extends Thread {
	@Override
	public void run() {
		for (int i = 1; i<=20; i++) {
			System.out.print("월요일" + i + "\t");
			if(i%5==0) System.out.println();
			try {
				sleep(100);
			} catch (InterruptedException e) {
			}
		}
	}
}

public class Threadtest3 {

	public static void main(String[] args) {
		ThreadExample2 te2 = new ThreadExample2();
		ThreadExample3 te3 = new ThreadExample3();
		te2.start();
		te3.start();
	}
}

출력 결과

 

 

ThreadTestHw3.java : 과제

package ch12;

//과제
//1. 생성자 이름을 가진 ThreadExample4 만들기
//2. 20번 돌아가면서 System.out.println(getName()+"대박"+i);
//3. 10/1000초 쉬기

//1. 생성자 이름을 가진 ThreadExample5 만들기
//2. 20번 돌아가면서 System.out.println(getName()+"월요일"+i);
//3. 50/1000초 쉬기

class ThreadExample4 extends Thread {
	public void run() {
		for (int i = 1; i<=20; i++) {
			setName("ThreadExample4...");
			System.out.print(getName() + "대박" + "\t");
			if(i%5==0) System.out.println();
			try {
				sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}
}

class ThreadExample5 extends Thread {
	public void run() {
		for (int i = 1; i<=20; i++) {
			setName("ThreadExample5...");
			System.out.print(getName() + "월요일" + i + "\t");
			if(i%5==0) System.out.println();
			try {
				sleep(50);
			} catch (InterruptedException e) {
			}
		}
	}
}	

public class ThreadTestHw3 {
	
	//과제
	//ThreadExample4, ThreadExample5 선언
	//인스턴스 명은 te4, te5
	//멀티 쓰레드로 실행시키기. -> .start()로 해야 함. .run()으로 하면 싱글스레드임.
	public static void main(String[] args) {
		ThreadExample4 te4 = new ThreadExample4();
		ThreadExample5 te5 = new ThreadExample5();
		te4.start();
		te5.start();
	}
}

//윗부분 정답코드
class ThreadExample41 extends Thread {
	ThreadExample41(String str) {
		super(str);
	}
	@Override
	public void run() {
		for (int i = 1; i<=20; i++) {
			System.out.println(getName() + "대박" + " \t");
			if(i%5==0) System.out.println();
			try {
				sleep(10);
			} catch (InterruptedException e) {
			}
		super.run();
	}
	}
}

출력 결과

 

 

ThreadTest5.java

package ch12;

import javax.swing.JOptionPane;

public class ThreadTest5 {

	public static void main(String[] args) throws InterruptedException {
		for (int i =0; i<10; i++) {
			System.out.println(i);
			Thread.sleep(1000);
		}
		String name = JOptionPane.showInputDialog("너 이름이 뭐니?");
		System.out.println("당신의 이름은 " + name + "입니다.");

	}

}

출력결과 : for문이 전부 실행된 뒤 다음 코드가 실행된다. (싱글스레드)

 

ThreadTest6.java

package ch12;

import javax.swing.JOptionPane;

//ThreadExample5을 멀티스레드로 돌리면 따로 돌아감.
//run이 돌아가는 도중에 main도 같이 돌아가는 것임.
class ThreadExample6 extends Thread {
	
	@Override
	public void run() {
		for (int i = 0; i <10; i++) {
			System.out.println(i);
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
		}
	}
	
}

public class ThreadTest6 {

	public static void main(String[] args) { 	//메인도 스레드임.
		ThreadExample6 te6 = new ThreadExample6();
		te6.start(); 	//메모리에 올라감
		
		String name = JOptionPane.showInputDialog("너 이름이 뭐니?");
		System.out.println("당신의 이름은 " + name + "입니다.");

	}

}

출력결과 : for문이 실행되는 도중 다음 코드가 실행된다. (멀티스레드)

 

 

Jointest.java

package ch12;

import java.util.ArrayList;

class Before extends Thread {
	Before(String str) {
		super(str);
	}
	void addCar() {
		System.out.println("addCar");
		//carList에 요소들 추가
		Jointest.carList.add("벤츠");
		Jointest.carList.add("아우디");
		Jointest.carList.add("SM7");
		Jointest.carList.add("포르쉐");
	}
	@Override
	public void run() {
		System.out.println(getName());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		}
		addCar();
	}
}

class After extends Thread {
	After(String str) {
		super(str);
	}
	@Override
	public void run() {
		System.out.println("After Thread 이름 : " + getName());	//getName은 스레드의 이름을 반환
		//Before class에서 추가했던 carList 요소들을 출력
		for(String car : Jointest.carList) {
			System.out.println(car);
		}
	}
}

public class Jointest {
	//carList는 인스턴스를 생성하지 않아도 쓸 수 있는 공유변수
	public static ArrayList<String> carList = new ArrayList<String>();
	
	public static void main(String[] args) {
		
		//af와 bf는 스레드이기 때문에 실행순서를 개발자가 정하지 못함. 
		//근데 위의 Beforeclass에서 값을 세팅하고 After에서 값을 프린트해서 봐야하는 것 처럼 순서를 정해야 할 때가 있음
		//그럴 땐 .join을 사용하여 before 스레드가 끝날 때까지 대기한 후 after 스레드를 실행함.
		Before bf = new Before("우선");
		After af = new After("나중에");
		bf.start();
		try {
			bf.join(); 		
		} catch (InterruptedException e) {
		}
		af.start();
	}
}

출력 결과

 

 

RunnableTest1.java

package ch12;

class Ra1 implements Runnable {
	@Override
	public void run() {		//run은 추상메소드이기 때문에 반드시 구현해야 함.
		for (int i=1; i<=20; i++) {
			System.out.print(i+"대박 "+Thread.currentThread().getName());
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
		
	}
	
}

class Ra2 implements Runnable {
	@Override
	public void run() {
		for (int i = 1; i<=20; i++) {
			System.out.print(i+"월요일 "+Thread.currentThread().getName());
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}
}

public class RunnableTest1 {

	public static void main(String[] args) {
		Ra1 r1 = new Ra1();
		Ra2 r2 = new Ra2();
		//implement 한 것은 반드시 아래와 같은 선언 후 사용
		Thread th1 = new Thread(r1,"Pr");
		Thread th2 = new Thread(r2, "no");
		th1.start();
		th2.start();
	}

}

출력 결과

 

ThreadTestHw5.java : 과제

package ch12;

import java.awt.desktop.ScreenSleepEvent;

//과제 : 출력 결과가 -와 *와 +가 랜덤하게 출력됨.

//Thread 상속받아서 System.out.print("-"); 20번 수행
class G1 extends Thread {
	@Override
	public void run() {
		// super.run();
		for (int i = 0; i < 20; i++) {
			System.out.print("-");
			if (i % 10 == 0)
				System.out.println();
			try {
				sleep(50);
			} catch (InterruptedException e) {
			}
		}
	}
}

//Runnable 구현해서 System.out.print("+"); 20번 수행
class G2 implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.print("+");
			if (i % 10 == 0)
				System.out.println();
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
			}
		}
	}

}

//Runnable 구현해서 System.out.print("*"); 20번 수행
class G3 implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.print("*");
			if (i % 10 == 0)
				System.out.println();
			try {
				Thread.sleep(50);
				;
			} catch (InterruptedException e) {
			}
		}
	}
}

public class ThreadTestHw5 {

	public static void main(String[] args) {
		// 각각 Thread 수헹
		G1 g1 = new G1();
		G2 g2 = new G2();
		G3 g3 = new G3();
		Thread th2 = new Thread(g2);
		Thread th3 = new Thread(g3);
		g1.start();
		th2.start();
		th3.start();
	}
}

 

출력 결과

 

Account2.java

package ch12;

public class Account2 {
	int total; 		//잔액
	Account2 (int total) { 		//생성자를 통해 잔액을 초기화
		this.total = total;
	}
	
	void deposit(int amt, String name) { 	//현재 예금 보여줌
		total += amt;
		System.out.println(name + "예금 : " + amt);
	}
	//synchronized 사용 시 동시접근 막는다.
	void withdraw ( int amt, String name) {		//출금
		if (amt <=total) { 		//amt가 total보다 크거나 작을 때만 출금
			total -= amt;
			System.out.println(name + "출금 : " + amt);
			getTotal();
		} else {		//그렇지 않으면 현재 잔액만 보여줌.
			System.out.println(name + "의 출금 요청 " + amt
					+"잔액부족 저금 좀 해 --> 현재 잔액 : " + total);
		}
	}
	void getTotal() {
		System.out.println("잔액 : " + total);
		
	}

}

 

Account2Ex.java

package ch12;

class Account2User extends Thread {
	Account2 act;
	boolean flag;
	public Account2User (Account2 act, String name) {
		super(name);
		this.act = act;
	}
	@Override
	public void run() {
		//다섯번을 돌려가면서 1초씩 쉰다.
		//flag가 1일 때만 deposit(저금), 0일때는 10000만원 이하의 돈을 랜덤하게 저금.
		//withdraw는 인출
		//한번은 저축하고 한번을 출금을 랜덤하게 함.
		for(int i = 0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();			
			} 
			//공통적으로 사용되는 요소에 대해 동기화 걸기.
			synchronized (act) { 	//동기화. act 기준으로 synchronized. act를 쓰고 있으면 대기
				if (flag) act.deposit((int) (Math.random()*10000), getName());
				else act.withdraw((int) (Math.random()*10000), getName());
				flag = !flag; 	//flag SWAP 	//출금과 예금을 계좌별 반복
			}
		}
	}
}

public class Account2Ex {

	public static void main(String[] args) {
		Account2 act1 = new Account2(10000); //10000원이 있는 여자그룹 계좌
		Account2 act2 = new Account2(15000); //15000원이 있는 남자그룹 계좌
		
		//여자그룹 (옥주현, 조정은, 정선아) / 남자그룹 (김준수, 전동석, 신성록) 
		//각 그룹끼리 같은 계좌를 쓰고 있음
		//누군가가 접근한 상태이면 다른사람들은 그 순간에는 접근하지 못함.
		Account2User au1 = new Account2User(act1, "옥주현");
		Account2User au2 = new Account2User(act1, "조정은");
		Account2User au3 = new Account2User(act1, "정선아");
		Account2User au4 = new Account2User(act2, "김준수");
		Account2User au5 = new Account2User(act2, "전동석");
		Account2User au6 = new Account2User(act2, "신성록");
		
		//스레드이기 때문에 각각 돌릴 수 있다.
		au1.start();
		au2.start();
		au3.start();
		au4.start();
		au5.start();
		au6.start();
	}
}

출력 결과

 

 

p.17 synchronized(동기화) (면접에서 물어볼 수 있음, 중요)

- 하나의 자원을 여러 태스크가 사용하려 할 때에, 한 시점에서 하나의 태스크만이 사용 할 수 있도록 하는 것

- 대부분의 응용 프로그램에서 다수개의 스레드가 공유할 수 있는 부분이 요구된다

- 공유부분은 상호 배타적으로 사용되어야 한다

- 임계영역(critical section)

① 상호배타적으로 사용되는 공유부분

② 자바는 한 순간에 하나의 스레드만 실행할 수 있는 synchronized method 제공

③ 한 스레드가 synchronized method를 수행 중이면 다른 스레드는 대기한다

 

 

[13.Lambda]

 

p.2

람다표현식('->' 표시가 람다 표현식임을 컴파일러에게 알려줌)

(int a, int b) -> {return a+b};

(int a, int b) -> a+b;

(a, b) -> a + b;

 

람다식

1) (매개변수)->{실행코드} 형태로 작성

2) 하나의 매개변수만 있다면 ()생략, 하나의 실행문만 있다면 {}도 생략

 

p.4 표준 API 함수적 Interface : 자바8 부터 java.util.function 패키지에 자주 사용되는 함수적 인터페이스를 표준 API로 제공

 

 

[ch13]

 

ConsumerEx.java

package ch13;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;

public class ConsumerEx {

	public static void main(String[] args) {
		//java8버전에서 consumer를 제공해줌.
		//외울 필요는 없고 찾아서 쓰면 됨.
        //실무에서는 이런식으로 쓰지 않음. 명령어 기억할 필요 없음.
        // 이론적인것은 이런 느낌. Spring 배울 때 다시 배울 예정
		Consumer<String> consumer = t->System.out.println(t+"8");
		//accept는 주어진 parameter를 가지고 argument를 실행한다.(하나만 넣음)
		consumer.accept("1.java"); 	
		//1.java가 t로 들어가서 System.out.println(t+"8");를 실행시켜주는 것임.
		//BiConsumer는 두개의 값을 입력하며 리턴값이 없다.
		BiConsumer<String, String> biConsumer = (t, u) ->System.out.println(t+u);
		biConsumer.accept("2.java", "20220801");
		//DoubleConsumer는 숫자를 double값으로 받음. 리턴값이 없다. 
		DoubleConsumer doubleConsumer = d -> System.out.println(100 + d);
		doubleConsumer.accept(8.0);
	}
}

출력 결과

 

 

Student.java

package ch13;

public class Student {
	private String name;
	private int englishScore;
	private int mathScore;
	
	public Student(String name, int englishScore, int mathScore) {
		this.name = name;
		this.englishScore = englishScore;
		this.mathScore = mathScore;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getEnglishScore() {
		return englishScore;
	}

	public void setEnglishScore(int englishScore) {
		this.englishScore = englishScore;
	}

	public int getMathScore() {
		return mathScore;
	}

	public void setMathScore(int mathScore) {
		this.mathScore = mathScore;
	}


}

 

FunctionEx1.java

package ch13;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

public class FunctionEx1 {
	
	private static List<Student> list = Arrays.asList(
			new Student("김준수", 90, 86),
			new Student("손흥민", 95, 73)			
			);
	
	// 파라미터에 student 값을 가져오면  ("김준수", 90, 86)등 각각의 객체가 list(static)형태로 들어가짐.
	public static void printString(Function<Student, String> function) {
		for(Student student : list) {
			//student에 있는 값을 k와 더해서 프린트한다.
			System.out.println(function.apply(student) + "k ");
		}
		System.out.println();
	}
	
	public static void printInt(ToIntFunction<Student> function) {
		for(Student student : list) {
			System.out.print(function.applyAsInt(student) + " ");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		System.out.println("[학생 이름]");
		//t.getName값만 뽑아준다.
		//내부적으로는 getname을 계속 돌려주면서 이름만 뽑아주는 것이다
		//16줄에 들어가는 것
		printString(t -> t.getName());
		
		System.out.println("[영어 점수]");
		//student의 getEnglishScore
		//24줄에 들어가는 것
		printInt(t -> t.getEnglishScore());
		
		//student 객체로 받았지만 getMathScore이 하나의 student 객체이기 때문에 이렇게 코드를 짰을 때 실행이 되는 것임.
		System.out.println("[수학 점수]");
		printInt(t -> t.getMathScore());

	}

}

출력 결과

 

반응형