
Java에서 기본 System.out.println()은 출력할 때마다 콘솔에 즉시 출력
반복문 안에서 수천 번 호출되면 시간 초과로 이어질 수 있음 그래서 버퍼에 모아뒀다가 한 번에 출력하는 방식
System.out은 바이트 스트림
BufferedWriter는 문자 스트림
중간에 OutputStreamWriter로 연결해줘야 함
데이터를 임시로 저장해두는 중간 저장 공간
CPU ↔ 메모리 ↔ 입출력 장치 사이에서 속도 차이를 줄이기 위해 존재
여러 프로세스 또는 스레드가 동시에 공유 자원에 접근할때,
예상치 못한 충돌이나 데이터 오류를 방지하기위해 접근 순서를 조정하는것
둘 이상의 프로세스*(또는 스레드)가 접근하면 안되는 코드 영역
공유 변수조작,파일 쓰기,은행 잔액 처리등
동기화의 핵심 대상
동시에 둘 이상이 임계 영역에 접근하지 못하게 하는 제어 기법
하나가 들어가있으면 하나는 기다려야함
Java에선 synchronized,Lock등으로 구현
대표 알고리즘 Peterson, Dekker, Bakery
임계영역에 아무도 없다면 들어가려는 프로세스중 하나는 반드시 진입해야함
특정 프로세스가 진입하지 못하는 상황을 막는 조건
프로세스간 양보/선택 알고리즘이 공정하게 작동해야함
어떤 프로세스도 무한히 기다리게해선 안됨
기다리면 언젠간 들어가야함
특정 프로세스가 계속 우선순위를 가져버리면 유한대기 조건 위반
서로 자원을 기다리다가 아무것도 못하는 상태
A는B가 점유한 자원 필요, B는A의 자원을 기다림
자원 회수 불가능 + 상호 대기 발생 -> 시스템 멈춤
자원 접근을 제한하는 정수형 변수
p() acquire 자원 감소
v() release 자원 증가
0이면 기다리고 양수면 들어감
상호 배제를 구현하는 간단한 도구 (하나만 접근 허용)
Java에선 synchronized,ReentrantLock등으로 구현
스레드가 자원 점유 끝나면 반드시 반납\
동기화된 코드와 데이터를 포괄하는 고급 개념
Java에선 객체단위로 동기화 가능
Sychronized method/block 모니터 진입 퇴장처럼 동작
하나의 모니터에 동시에 하나만 들어올 수 있음
| 항목 | synchronized | ReentrantLock |
|---|---|---|
| 기본 락/언락 방식 | 자동 처리 (synchronized 키워드로 잠금/해제) | 수동 처리 (lock() / unlock() 직접 호출) → try-finally 블록 권장 |
| 락 상태 확인 | ❌ 불가 | ✅ isLocked(), isHeldByCurrentThread() 등으로 상태 확인 가능 |
| 타임아웃 락 지원 | ❌ 불가 | ✅ tryLock(timeout) 사용 가능 |
| 조건 변수 지원 | ❌ 없음 | ✅ Condition 객체를 통한 세밀한 wait/notify 제어 가능 (await(), signal()) |
| 공정성 설정(FIFO) | ❌ 없음 | ✅ 생성 시 new ReentrantLock(true)로 공정성(FIFO 방식) 보장 가능 |
| 기능 요약 | - 간편한 기본 동기화 - 세밀한 제어 불가 - 사용이 쉬워 간단한 상황에 적합 | - 고급 동기화 기능 다수 - 수동 처리 필요하지만 유연하고 강력 - 복잡한 동시성 처리나 생산자-소비자 문제에 적합 |
첫째 줄에는 별 1개, 둘째 줄에는 별 2개, N번째 줄에는 별 N개를 찍는 문제
입력
첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다.
첫째 줄부터 N번째 줄까지 차례대로 별을 출력한다.
5
package loop;
import java.util.Scanner;
public class BOJ_2438_Star1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String m = "";
for (int i = 1; i <= n; i++) {
m +="*";
System.out.println(m);
}
sc.close();
}
}
반복문을 사용한 특정 출력 패턴 확인 문제
첫째 줄에는 별 1개, 둘째 줄에는 별 2개, N번째 줄에는 별 N개를 찍는 문제
하지만, 오른쪽을 기준으로 정렬한 별(예제 참고)을 출력하시오.
첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다.
첫째 줄부터 N번째 줄까지 차례대로 별을 출력한다.
5
*
**
package loop;
import java.util.Scanner;
public class BOJ_2439_Star2 {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=n-i;j++){
System.out.print(" ");
}
for(int k=1;k<=i;k++){
System.out.print("*");
}
System.out.println();
}
sc.close();
}
}
어려웠음 중첩반복문의 이해를 물어보는 문제 for 문의 비교 대상이 n 인가 i 인가 를 잘 생각 하고 풀어야 하는 문제
두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.
입력은 여러 개의 테스트 케이스로 이루어져 있다.
각 테스트 케이스는 한 줄로 이루어져 있으며, 각 줄에 A와 B가 주어진다. (0 < A, B < 10)
입력의 마지막에는 0 두 개가 들어온다.
각 테스트 케이스마다 A+B를 출력한다.
1 1
2 3
3 4
9 8
5 2
0 0
2
5
7
17
7
package loop;
import java.util.Scanner;
public class BOJ_10952_APlusB4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
boolean cal = true;
while (cal) {
int a = sc.nextInt();
int b = sc.nextInt();
if ((a + b)==0) {
cal = false;
}else{
System.out.println(a+b);
}
}
sc.close();
}
}
While문을 사용해서 푸는 문제
int a, b;
while ((a = sc.nextInt()) + (b = sc.nextInt()) != 0) {
System.out.println(a + b);
}
이런식으로 문제를 간략하게 풀 수도 있음 …
생산자 2개 소비자 2개인 상황에서 서로 자원을 공유하며 비동기 협업하는 구조
synchronized로 임계영역 보호 1개의 쓰레드만 들어와서 생산
생산 완료 소비자 깨움 소비자도 보호되어있어서 1개의 쓰레드만 들어와서 소비
버퍼가 가득차면 생산자 대기 버퍼 비어있으면 소비자 대기
이 구조는 생산자/소비자가 동시에 작동하되, synchronized 키워드와 wait()/notifyAll()를 통해 서로 협력하며 안정적으로 자원을 공유하도록 설계되어 있음
실행 순서는 JVM 스케줄러에 따라 달라지지만, 동기화 구조 덕분에 항상 안전하게 동작함
Exception 객체인 e가 가진 정보를 터미널(콘솔)에 출력해주는 메서드
주로 try-catch 블록 안에서 예외가 발생했을 때 디버깅용으로 사용됨
import java.util.LinkedList;
import java.util.Queue;
public class MultiBuffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 3;
public synchronized void produce(int val) {
while (queue.size() == CAPACITY) {
try {
System.out.println(Thread.currentThread().getName() + " ⛔ 버퍼 가득. 대기 중");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(val);
System.out.println(Thread.currentThread().getName() + " 🔼 생산: " + val);
notifyAll(); // 소비자 깨움
}
public synchronized void consume() {
while (queue.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName() + " ⛔ 버퍼 없음. 대기 중");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int val = queue.poll();
System.out.println(Thread.currentThread().getName() + " 🔽 소비: " + val);
notifyAll(); // 생산자 깨움
}
}
public class MultiProducerConsumerTest {
public static void main(String[] args) {
MultiBuffer buffer = new MultiBuffer();
// 생산자 2명
for (int i = 1; i <= 2; i++) {
int id = i;
new Thread(() -> {
for (int j = 1; j <= 5; j++) {
buffer.produce(j + (id * 100));
try { Thread.sleep(200); } catch (InterruptedException e) {}
}
}, "👷 생산자-" + i).start();
}
// 소비자 2명
for (int i = 1; i <= 2; i++) {
new Thread(() -> {
for (int j = 1; j <= 5; j++) {
buffer.consume();
try { Thread.sleep(300); } catch (InterruptedException e) {}
}
}, "🧺 소비자-" + i).start();
}
}
}
👷 생산자-1 🔼 생산: 101
👷 생산자-2 🔼 생산: 201
👷 생산자-1 🔼 생산: 102
👷 생산자-2 ⛔ 버퍼 가득. 대기 중
🧺 소비자-1 🔽 소비: 101
👷 생산자-2 🔼 생산: 202
🧺 소비자-2 🔽 소비: 201
...
| 요소 | 설명 |
|---|---|
ReentrantLock | - 직접 lock() / unlock() 호출해야 함 (수동 락)- try-finally 블록으로 예외 처리 필요 |
Condition | - await() / signal() / signalAll() 사용- 기존 wait() / notifyAll() 대체 가능 |
| 장점 | - 공정성 설정 (new ReentrantLock(true))- 락 상태 확인 ( isLocked(), isHeldByCurrentThread() 등)- 다양한 조건 변수 사용 가능 (멀티 대기방) |
생산자 2명 소비자 2명
ReentrantLock으로 임계영역 보호
Codition으로 생산자 소비자 대기 깨우기 제어
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class LockBuffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 3;
private final ReentrantLock lock = new ReentrantLock(); // 수동 락
private final Condition notFull = lock.newCondition(); // 생산자 대기 조건
private final Condition notEmpty = lock.newCondition(); // 소비자 대기 조건
public void produce(int val) {
lock.lock(); // 🔐 락 획득
try {
while (queue.size() == CAPACITY) {
System.out.println(Thread.currentThread().getName() + " ⛔ 버퍼 가득. 대기 중");
notFull.await(); // 생산자 대기
}
queue.add(val);
System.out.println(Thread.currentThread().getName() + " 🔼 생산: " + val);
notEmpty.signal(); // 소비자 1명 깨움
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 🔓 락 해제
}
}
public void consume() {
lock.lock();
try {
while (queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " ⛔ 버퍼 없음. 대기 중");
notEmpty.await(); // 소비자 대기
}
int val = queue.poll();
System.out.println(Thread.currentThread().getName() + " 🔽 소비: " + val);
notFull.signal(); // 생산자 1명 깨움
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class LockProducerConsumerTest {
public static void main(String[] args) {
LockBuffer buffer = new LockBuffer();
// 생산자 2명
for (int i = 1; i <= 2; i++) {
int id = i;
new Thread(() -> {
for (int j = 1; j <= 5; j++) {
buffer.produce(j + (id * 100));
try { Thread.sleep(200); } catch (InterruptedException e) {}
}
}, "👷 생산자-" + i).start();
}
// 소비자 2명
for (int i = 1; i <= 2; i++) {
new Thread(() -> {
for (int j = 1; j <= 5; j++) {
buffer.consume();
try { Thread.sleep(300); } catch (InterruptedException e) {}
}
}, "🧺 소비자-" + i).start();
}
}
}
| 기능 | synchronized 방식 | ReentrantLock + Condition 방식 |
|---|---|---|
| 락/언락 방식 | 자동 (synchronized 키워드 사용, try-finally 불필요) | 수동 (lock() / unlock() 직접 호출, try-finally 권장) |
| 대기 메서드 | wait() 사용 | await() 사용 |
| 신호 메서드 | notify(), notifyAll() 사용 | signal(), signalAll() 사용 |
| 대기방(Condition) | 1개 고정 | 여러 개 조건 변수 생성 가능 (newCondition()으로 분리된 대기방 설정) |
| 락 상태 확인 | ❌ 불가능 | ✅ isLocked(), isHeldByCurrentThread() 등으로 확인 가능 |
| 타임아웃 락 | ❌ 지원하지 않음 | ✅ tryLock(timeout) 가능 |
| 조건 변수 분리 | ❌ 불가 (1개 wait()만 존재) | ✅ 가능 (예: notFull, notEmpty 등 다중 조건 대기 가능) |
| 공정성 설정 | ❌ 불가 | ✅ 가능 (new ReentrantLock(true)로 FIFO 방식 스케줄링 설정) |
단순한 상황은 synchronized 복잡할땐 ReentrantLock+Condition
데이터 타입을 클래스나 메서드를 선언할 때 결정하지 않고, 사용할 때 지정하는 방법.타입을 일반화(generalize)하여, 재사용성과 안정성을 높임.
타입을 정해두지 않아서 어떤 타입이든 받은대로 나감
public class Box<T> {
private T item;
public void set(T item) { this.item = item; }
public T get() { return item; }
}
public class Util {
public static <T> void print(T value) {
System.out.println(value);
}
}
Box<String> strBox = new Box<>();
strBox.set("Hello");
System.out.println(strBox.get()); // Hello
Box<Integer> intBox = new Box<>();
intBox.set(123);
System.out.println(intBox.get()); // 123
Util.print("제네릭 테스트"); // 제네릭 테스트
Util.<Double>print(3.14); // 3.14
Null 방지용 안전 래퍼 클래스
Optional 의 메소드에 따라 true/false 출력함
NullPointerException 예방
메서드 리턴값으로 값이 없을 수도 있다"는 걸 명확하게 전달
if문이나 try-catch 없이도 null 체크가 가능
| 메서드 | 설명 | 예시 |
|---|---|---|
of() | null이 아닌 값을 감쌈 | Optional.of("값") |
ofNullable() | null도 감쌀 수 있음 | Optional.ofNullable(name) |
isPresent() | 값이 존재하는지 여부 확인 (true/false) | if (opt.isPresent()) |
ifPresent() | 값이 있을 때만 실행 | opt.ifPresent(val -> ...) |
orElse() | 값이 없으면 기본값 반환 | opt.orElse("기본") |
orElseThrow() | 값이 없으면 예외 발생 | opt.orElseThrow(() -> new Exception()) |
Optinal<String> name = Optinal.of<“도리”>;
새로운 집합을 생성하는 자료구조
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> names = new HashSet<>();
names.add("도리");
names.add("윤동찬");
names.add("도리"); // 중복 무시됨
for (String name : names) {
System.out.println(name);
}
}
}
key와 value를 가지고 있는 집합
Keys는 중복 안되나 value 중복은 가능함
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
Map<String, Integer> scoreMap = new HashMap<>();
scoreMap.put("도리", 90);
scoreMap.put("윤동찬", 95);
scoreMap.put("도리", 85); // 같은 키면 덮어씀
for (String name : scoreMap.keySet()) {
System.out.println(name + "의 점수: " + scoreMap.get(name));
}
}
}
| 자료구조 | 집합? | 특징 | 중복 허용 | 순서 보장 |
|---|---|---|---|---|
int[], String[] (배열) | ✅ | 고정된 크기, 빠른 인덱스 접근 | ✅ | ✅ (인덱스 순서) |
List<String> (ArrayList 등) | ✅ | 크기 유동적, 인덱스 기반 | ✅ | ✅ (삽입 순서 유지) |
Set<String> | ✅ | 중복 자동 제거 | ❌ | ❌ (HashSet), ✅ (LinkedHashSet) |
Map<String, Integer> | ✅ (Key-Value) | Key → Value 쌍, Key는 중복 불가 | Key ❌, Value ⭕ | ❌ (HashMap), ✅ (LinkedHashMap) |
아내 생일을 지난 다음날 부터 몸살이 나서 무려 3일을 내리 쉬는 말도 안되는 일을 저질렀습니다
이래서 운동을 하면서 체력을 늘릴려고 한건데 … 아침에 일어나서 운동은 쉽지 않네요
백준 3문제를 풀었는데 잘 풀었습니다만..
역시 gpt한테 물어보고 받은 답은 참 충격적이네요
그래도 알고리즘을 이해하면서 하고 있다는게 자랑스럽습니다
오늘 2개를 쓸려고하는데 될지 모르겠네요 일단 열심히 해볼려구요
cs공부를할려고 면접을 위한 cs전공지식 노트를 샀는데 뭔 내용인지 하나도 모르겟어서
좀 찾아보니까 이거 좀 아는 사람들의 복습용이라고 하더라고요
다른 방식을 생각을 해봤습니다 ..
기초부터 다지는 일단 언어 하나를 때고 해야될거같아서 지금처럼
java+백준 하면서 알고리즘 + 언어의 문법을 좀 마스터하고
운영체제와 동기화에 대해서 공부를 한뒤에API 기반 연습하고
네트워크, DB 연계 후반부에 패턴, JVM 등 중급 개념 이렇게 해보겠습니다
동기화까지 좀 했으니까다른 자료들 찾아보면서 쭉쭉 가보겠습니다
근데 진짜 뭐가 많네요 개발자분들 진짜 존경합니다 …
제네릭도 한번 써서 다 안다고 생각햇는데
이게 나무 줄기처럼 쭉쭉 이어지니까 끝이 없네요 그래도 재미있습니다..
쉰만큼 열심히 하겠습니다