μΌ | μ | ν | μ | λͺ© | κΈ | ν |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- νμ΄μ¬ μ±λ¦°μ§
- λ¬μ€νΈ
- λ°±μ€
- Rust
- λ°μ΄ν°λ² μ΄μ€
- ubuntu
- μ€λΌν΄DB
- μλ° κΈ°μ΄
- java
- C
- μ°λΆν¬
- μκ³ λ¦¬μ¦
- νμ΄μ¬
- Python challenge
- λ¬μ€νΈ μμ
- λ°μ΄ν° ν΅μ
- μ€λΌν΄
- μλ° κ°λ
- Reversing
- Database
- νμ΄μ¬ μκ³ λ¦¬μ¦
- μλ°
- data communication
- νμ΄μ¬ μ²Όλ¦°μ§
- Operating System
- λ¬μ€νΈ νλ‘κ·Έλλ° κ³΅μ κ°μ΄λ
- μ΄μ체μ
- OS
- Python
- λ°±μ€ λ¬μ€νΈ
Archives
- Today
- Total
IT’s Portfolio
[Java] Lecture - Day 16 λ³Έλ¬Έ
728x90
λ°μν
π₯ Basic Java - Day 16
ππ» [Chapter 12] μλ° μ€λ λ κΈ°μ΄
λ©ν°νμ€νΉ
- Multi Tasking
- νλμ μμ© νλ‘κ·Έλ¨μ΄ μ¬λ¬ κ°μ μμ (νμ€ν¬)μ λμ μ²λ¦¬
- λ©ν°νλ‘μΈμ±(multi-processing)
- νλμ μμ© νλ‘κ·Έλ¨μ΄ μ¬λ¬ κ°μ νλ‘μΈμ€λ₯Ό μμ±νκ³ , κ° νλ‘μΈμ€κ° νλμ μμ μ μ²λ¦¬νλ κΈ°λ²
- κ° νλ‘μΈμ€λ λ 립λ λ©λͺ¨λ¦¬ μμμ 보μ νκ³ μ€ν
- νλ‘μΈμ€λ€κ° ν΅μ (IPC; Inter Process Communication)κ³Ό νλ‘μΈμ€ μ¬μ΄μ λ¬Έλ§₯ κ΅ν(Context Switching)μ λ°λ₯Έ κ³Όλν μ€λ²ν€λμ μκ° μλͺ¨μ λ¬Έμ μ
- λ©ν°μ€λ λ©(multi-threading)
- νλμ μμ© νλ‘κ·Έλ¨μ λμ μ²λ¦¬κ° κ°λ₯ν μ¬λ¬ μμ μΌλ‘ λΆν
- νλμ μμ© νλ‘κ·Έλ¨μ΄ μ¬λ¬ κ°μ μ€λ λλ₯Ό μμ±νμ¬, κ° μ€λ λκ° νλμ μμ μ μ²λ¦¬νλ κΈ°λ²
- νλμ μμ© νλ‘κ·Έλ¨μ μν μ€λ λλ€μ μμκ³Ό λ©λͺ¨λ¦¬(λ³μ, νμΌ μ€ν ν μ΄λΈ λ±)λ₯Ό 곡μ νλ―λ‘, μ€λ λκ° ν΅μ κ³Ό λ¬Έλ§₯ κ΅νμ λ°λ₯Έ μ€λ²ν€λκ° μ μ΄ λΉ λ¦
μ€λ λ
- Thread
- Thread of Controlμ μ€λ§
- νλ‘κ·Έλ¨μ μ€ννλ νλμ μ€, μ μ΄
- μ΄μ체μ μμ μμ μ μ€ννκ³ κ΄λ¦¬νλ λ¨μ
- ꡬμ±
- μ€λ λ μ½λ
- μμ μ€νμ μν΄ μμ±ν νλ‘κ·Έλ¨ μ½λ
- κ°λ°μκ° μμ±
- μ€λ λ μ 보
- μ΄μ체μ κ° μ€λ λμ λν΄ κ΄λ¦¬νλ μ 보
- μ€λ λ λͺ , ID, μ€ν μμ μκ°, μ°μ μμ
- μ€λ λ μ½λ
- μ€λ λμ μ΄μ체μ
- μ€λ λλ λ€λ₯Έ μ€λ λλ₯Ό μμ± λ° μ€λ¨μν€κΈ° μν΄ μ΄μ체μ λ₯Ό ν΅ν΄ μ΄λ₯Ό μν
- μ€λ λλ₯Ό μμ±, μ€λ¨, μ’ λ£μν€κ³ μ€νν μ€λ λλ₯Ό μ€μΌμ₯΄λ§νλ κΆνμ μ΄μ체μ μ μμ
- μλ°μ μ€λ λ
- JVMμ μν΄ μ€μΌμ₯΄λλ μ€ν λ¨μμ μ½λ λΈλ
- μ€λ λμ μλͺ μ£ΌκΈ°(μ€ν, λ©μΆ€, μ’ λ£ λ±)λ JVMμ μν΄ κ΄λ¦¬λ¨
- JVMμ μ€λ λ λ¨μλ‘ μ€μΌμ₯΄λ§
- JVMκ³Ό λ©ν°μ€λ λμ κ΄κ³
- νλμ JVMμ νλμ μλ° μμ© νλ‘κ·Έλ¨λ§ μ€ν
- μλ° μμ© νλ‘κ·Έλ¨μ΄ μμλ λ JVMμ΄ ν¨κ» μ€νλ¨
- μλ° μμ© νλ‘κ·Έλ¨μ΄ μ’ λ£λλ©΄ JVMλ ν¨κ» μ’ λ£λ¨
- νλμ μμ© νλ‘κ·Έλ¨μ νλ μ΄μμ μ€λ λλ‘ κ΅¬μ± κ°λ₯
- νλμ JVMμ νλμ μλ° μμ© νλ‘κ·Έλ¨λ§ μ€ν
μλ°μμ μ€λ λ λ§λ€κΈ°
- java.lang.Thread ν΄λμ€λ₯Ό μμλ°μ μ€λ λ μμ±
- java.lang.Runnable μΈν°νμ΄μ€λ₯Ό ꡬννμ¬ μ€λ λ μμ±
Thread() // μ€λ λ κ°μ²΄ μμ±
Thread(Runnable target) // Runnable κ°μ²΄μΈ targetμ μ΄μ©νμ¬ μ€λ λ κ°μ²΄ μμ±
Thread(String name) // μ΄λ¦ nameμΈ μ€λ λ κ°μ²΄ μμ±
Thread(Runnable target, String name) // Runnable κ°μ²΄λ₯Ό μ΄μ©νλ©°, μ΄λ¦μ΄ nameμΈ μ€λ λ κ°μ²΄ μμ±
- Thread ν΄λμ€ μμ±μ
void run() // μ€λ λ μ½λλ‘μ JVMμ μν΄ νΈμΆλ¨. ν΄λΉ λ©μλ μ’
λ£ μ μ€λ λλ μ’
λ£
void start() // JVMμκ² μ€λ λ μ€ν μμ μμ²
void interrupt() // μ€λ λ κ°μ μ’
λ£
static void yield() // λ€λ₯Έ μ€λ λμκ² μ€ν μ보. JVMμ μ€λ λ μ€μΌμ₯΄λ§μ μννλ©° λ€λ₯Έ μ€λ λ μ ν μ€ν
void join() // μ€λ λ μ’
λ£ μκΉμ§ κΈ°λ€λ¦Ό
long getId() // μ€λ λ ID κ° λ¦¬ν΄
String getName() // μ€λ λ μ΄λ¦ 리ν΄
int getPriority() // μ€λ λ μ°μ μμ 리ν΄(1~10)
void setPriority(int n) // μ€λ λ μ°μ μμ λ³κ²½
Thread.State getState() // μ€λ λ μν 리ν΄
static void sleep(long mills) // μ€λ λ mills μκ° λμ μ μ§
static Thread currentThread() // νμ¬ μ€ν μ€μΈ μ€λ λ κ°μ²΄ λ νΌλ°μ€ 리ν΄
- Thread ν΄λμ€ μ£Όμ λ©μλ
import java.awt.*;
import javax.swing.*;
class TimerThread extends Thread {
private JLabel time;
public TimerThread(JLabel time) {
this.time = time;
}
@Override
public void run() {
int n = 0;
while(true) {
time.setText(Integer.toString(n));
n++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
public class Thread01 extends JFrame {
Thread01() {
super("Thread Exam 01");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
Container c = getContentPane();
c.setLayout(new FlowLayout());
JLabel timer = new JLabel();
timer.setFont(new Font("Gothic", Font.ITALIC, 80));
c.add(timer);
TimerThread th = new TimerThread(timer);
setVisible(true);
th.start();
}
public static void main(String[] args) {
new Thread01();
}
}
- Threadλ₯Ό μμλ°μ 1μ΄ λ¨μμ νμ΄λ¨Έ μμ
interface Runnable {
public void run();
}
- Runnable μΈν°νμ΄μ€
import java.awt.*;
import javax.swing.*;
class TimerRunnable implements Runnable {
private JLabel timer;
TimerRunnable(JLabel timer) {
this.timer = timer;
}
@Override
public void run() {
int n = 0;
while(true) {
timer.setText(Integer.toString(n));
n++;
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
return;
}
}
}
}
public class Thread02 extends JFrame {
Thread02() {
super("Thread Exam 02");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
Container c = getContentPane();
JLabel timer = new JLabel();
c.setLayout(new FlowLayout());
timer.setFont(new Font("Gothic", Font.ITALIC, 80));
c.add(timer);
TimerRunnable tr = new TimerRunnable(timer);
Thread th = new Thread(tr);
setVisible(true);
th.start();
}
public static void main(String[] args) {
new Thread02();
}
}
- Runnable μΈν°νμ΄μ€λ₯Ό ꡬννμ¬ 1μ΄ λ¨μμ νμ΄λ¨Έ μμ
μ€λ λ μ£Όμ μ¬ν
- run() λ©μλ μ’
λ£ μ μ€λ λ μ’
λ£
- μ€λ λ μ§μμ μν μ run() λ©μλ λ΄μμ 무ν루ν μμ±
- ν λ² μ’
λ£ν μ€λ λ λ€μ μμ λΆκ°λ₯
- λ€μ μ€λ λ κ°μ²΄ μμ± ν start() νΈμΆ
- ν μ€λ λμμ λ€λ₯Έ μ€λ λ κ°μ μ’ λ£ κ°λ₯
μ€λ λ μ 보
- μ€λ λ μ΄λ¦: μ€λ λ μ΄λ¦μΌλ‘ μ¬μ©μκ° μ§μ
- μ€λ λ ID: μ€λ λ κ³ μ μ μλ³μ λ²νΈ
- μ€λ λ PC(Program Count): νμ¬ μ€ν μ€μΈ μ€λ λ μ½λμ μ£Όμ
- μ€λ λ μν
- NEW
- μ€λ λκ° μμ±λμμ§λ§ μ€λ λκ° μμ§ μ€νν μ€λΉκ° λμ§ μμμ
- RUNNABLE
- μ€λ λκ° νμ¬ μ€νλκ³ μκ±°λ, μ€ν μ€λΉλμ΄ μ€μΌμ€λ§μ κΈ°λ€λ¦¬λ μν
- WAITING
- wait() νΈμΆ μν
- λ€λ₯Έ μ€λ λκ° notify()λ notifyAll()μ λΆλ¬μ£ΌκΈ°λ₯Ό κΈ°λ€λ¦¬κ³ μλ μν
- μ€λ λ λκΈ°νλ₯Ό μν΄ μ¬μ©
- wait() νΈμΆ μν
- TIMED_WAITING
- sleep(n)μ νΈμΆνμ¬ n λ°λ¦¬μ΄ λμ μ μ§ν΄μλ μν
- BLOCK
- μ€λ λκ° I/O μμ μ μμ²νλ©΄ JVMμ΄ μλμΌλ‘ BLOCK μνλ‘ λ§λ¦
- TERMINATED
- μ€λ λκ° μ’ λ£ν μν
- NEW
- μ€λ λ μ°μ μμ: μ€λ λ μ€μΌμ€λ§ μ μ¬μ©λλ κ°μΌλ‘ 1~10 μ¬μ΄ κ°μ΄λ©° 10μ΄ μ΅μμ μ°μ μμ
- 10(MAX_PRIORITY)
- 1(MIN_PRIORITY)
- 5(NORMAL_PRIORITY)
- main() μ€λ λμ μ°μ μμλ μ΄κΈ° 5
- μ€λ λλ λΆλͺ¨ μ€λ λμ λμΌ μ°μ μμλ₯Ό κ°μ§κ³ νμ
- JVMμ μ€μΌμ₯΄λ§ μ μ±
- μ² μ ν μ°μ μμ κΈ°λ°
- κ°μ₯ λμ μ°μ μμ μ€λ λκ° μ°μ μ μ€μΌμ₯΄λ§
- λμΌ μ°μ μμ μ€λ λλ λμκ°λ©΄μ μ€μΌμ₯΄λ§(λΌμ΄λ λ‘λΉ)
- μ² μ ν μ°μ μμ κΈ°λ°
- μ€λ λ κ·Έλ£Ή: μ¬λ¬ κ°μ μλ° μ€λ λκ° νλμ κ·Έλ£Ήμ νμ±ν μ μμΌλ©° μ΄ κ²½μ° μ€λ λκ° μν κ·Έλ£Ή
- μ€λ λ λ μ§μ€ν° μ€ν: μ€λ λκ° μ€νλλ λμ λ μ§μ€ν°λ€μ κ°
main μ€λ λ
- JVMμ΄ μλ° μμ© νλ‘κ·Έλ¨ μ€ν μμ μ λν΄νΈλ‘ μμ±λλ μ€λ λ
- JVMμ main μ€λ λμκ² main() λ©μλλ₯Ό μ€νμΌ ν¨
- main() λ©μλκ° μ’ λ£νλ©΄ main μ€λ λ μ’ λ£
μ€λ λ μ’ λ£μ ν μ€λ λ κ°μ μ’ λ£
public void run() {
...
return;
...
}
- μ€μ€λ‘ μ’
λ£
- run() μ€ν λμ€ λ¦¬ν΄
- run()μ μμ ν μ€ννμ¬ μ’ λ£
B.interrupt()
- κ°μ μ’
λ£
- ν μ€λ λκ° λ€λ₯Έ μ€λ λλ₯Ό κ°μ μ’ λ£
- μ’ λ£νκ³ μ νλ μ€λ λμ interrupt() λ©μλ νΈμΆ
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.*;
public class Thread03 extends JFrame implements Runnable {
private Thread th;
Thread03() {
super("Thread Exam 03");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLocation(300, 300);
getContentPane().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(!th.isAlive()) return;
th.interrupt();
}
});
setVisible(true);
th = new Thread(this);
th.start();
}
@Override
public void run() {
Random r = new Random();
while(true) {
try {
Thread.sleep(20);
} catch(InterruptedException e) {
return;
}
int x = getX()+r.nextInt()%5;
int y = getY()+r.nextInt()%5;
setLocation(x, y);
}
}
public static void main(String[] args) {
new Thread03();
}
}
- μ§λνλ μ€λ λμ μ€λ λ κ°μ μ’ λ£ μμ
μ€λ λμ μμκ³Ό μ’ λ£
- λ©ν°μ€λ λλ₯Ό κ°μ§ νλ‘κ·Έλ¨μ λ€μ κ°μ μ€ν νλ¦μ κ°μ§
- start()μ μν΄ λ€μ€ νλ¦ μμ
- λ€μ κ°μ μ€ν νλ¦μ λ€μ νλμ νλ¦μΌλ‘ ν΅ν©νκΈ° μν΄μ μ€λ λκ° μ’
λ£λλ μμ μμ join() μ¬μ©
- InterruptedException μ²λ¦¬ μν¨
μ€λ λ λκΈ°ν
- Thread Synchronization
- λ©ν°μ€λ λ νλ‘κ·Έλ¨ μμ± μ μ£Όμμ
- λ€μμ μ€λ λκ° κ³΅μ λ°μ΄ν°μ λμ μ κ·Όνλ κ²½μ°, 곡μ λ°μ΄ν°μ κ°μ μμμΉ λͺ»ν κ²°κ³Όκ° λ°μν μ μμ
- μ€λ λ μ¬μ΄μ μ€νμμ μ μ΄, 곡μ λ°μ΄ν°μ λν μ κ·Όμ μννκ² νλ κΈ°λ²
- λκΈ°ν ν΅μ¬: μ€λ λμ 곡μ λ°μ΄ν°μ λν λ°°νμ λ μ μ κ·Ό 보μ₯
- λ©ν°μ€λ λμ 곡μ λ°μ΄ν° λμ μ κ·Ό λ¬Έμ ν΄κ²°μ±
- 곡μ λ°μ΄ν°λ₯Ό μ κ·Όνλ λͺ¨λ μ€λ λμ ν μ€ μΈμ°κΈ°
- ν μ€λ λκ° κ³΅μ λ°μ΄ν°μ λν μμ μ λλΌ λκΉμ§ λ€λ₯Έ μ€λ λκ° λκΈ°νλλ‘ ν¨
- μλ°μμ μ€λ λ λκΈ°νλ₯Ό μν λ°©λ²
- synchronized ν€μλλ‘ λκΈ°ν λΈλ‘ μ§μ
- wait()-notify() λ©μλλ‘ μ€λ λ μ€ν μμ μ μ΄
- λ©ν°μ€λ λ νλ‘κ·Έλ¨ μμ± μ μ£Όμμ
synchronized λΈλ‘ μ§μ
- synchronized ν€μλ
- ν μ€λ λκ° λ
μ ν΄μ μ€νν΄μΌ νλ λΆλΆ(λκΈ°ν μ½λ)μ νμνλ ν€μλ
- μκ³ μμ(critical section) νκΈ° ν€μλ
- λ©μλ μ 체 νΉμ μ½λ λΈλ‘μ synchronized λΈλ‘μΌλ‘ μ§μ
- ν μ€λ λκ° λ
μ ν΄μ μ€νν΄μΌ νλ λΆλΆ(λκΈ°ν μ½λ)μ νμνλ ν€μλ
- synchronized λΈλ‘μ λν μ»΄νμΌλ¬μ μ²λ¦¬
- λΈλ‘ μ§μ μ λ½μ΄ κ±Έλ¦¬κ³ (lock), λΈλ‘μμ λΉ μ Έλμ¬ μ λ½μ΄ νλ¦Ό(unlock)
public class Thread04 {
static SharedPrinter p = new SharedPrinter(); // 곡μ λ°μ΄ν° μμ±
private static String [] engText = { "Wise men say, ",
"only fools rush in",
"But I can't help, ",
"falling in love with you",
"Shall I stay? ",
"Would it be a sin?",
"If I can't help, ",
"falling in love with you" };
private static String [] korText = { "λν΄λ¬Όκ³Ό λ°±λμ°μ΄ λ§λ₯΄κ³ λ³λλ‘, ",
"νλλμ΄ λ³΄μ°νμ¬ μ°λ¦¬ λλΌ λ§μΈ",
"무κΆν μΌμ²λ¦¬ νλ €κ°μ°, ",
"λν μ¬λ λνμΌλ‘ κΈΈμ΄ λ³΄μ νμΈ",
"λ¨μ° μμ μ μλ무, μ² κ°μ λλ₯Έ λ―",
"λ°λμ리 λΆλ³ν¨μ μ°λ¦¬ κΈ°μμΌμΈ.",
"무κΆν μΌμ²λ¦¬ νλ €κ°μ°, ",
"λν μ¬λ λνμΌλ‘ κΈΈμ΄ λ³΄μ νμΈ" };
public static void main(String[] args) {
Thread th1 = new WorkerThread(p, engText);
Thread th2 = new WorkerThread(p, korText);
th1.start();
th2.start();
}
}
class SharedPrinter { // WorkerThreadμ μν΄ λμ μ κ·Όλλ ν΄λμ€
synchronized void print(String text) { // synchronized μλ΅ μ νκΈκ³Ό μμ΄κ° ν μ€μ μμ¬ μΆλ ₯λλ κ²½μ° λ°μ
for(int i=0; i<text.length(); i++)
System.out.print(text.charAt(i));
System.out.println();
}
}
class WorkerThread extends Thread { // μ€λ λ ν΄λμ€
private SharedPrinter p;
private String[] text;
WorkerThread(SharedPrinter p, String[] text) {
this.p = p; this.text = text;
}
@Override
public void run() {
for(int i=0;i<text.length; i++)
p.print(text[i]);
}
}
- sychronized λΈλ‘ μμ
wait()-notify()
- producer-consumer λ¬Έμ
- 곡μ λ©λͺ¨λ¦¬λ₯Ό ν΅ν΄ λ κ° μ΄μμ μ€λ λκ° λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ λ, μ€λ λλ€μ΄ 곡μ λ©λͺ¨λ¦¬λ₯Ό λμ μ κ·Όνλ λ¬Έμ
- producer-consumer λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν μ€λ λ λκΈ°ν λ©μλ
- Objectμ λ©μλ, synchronized λΈλ‘ λ΄μμλ§ μ¬μ©λμ΄μΌ ν¨
- wait(): λ€λ₯Έ μ€λ λκ° notify()λ₯Ό νΈμΆν λκΉμ§ λκΈ°
- notify(): λκΈ°νκ³ μλ μ€λ λλ₯Ό κΉ¨μ RUNNABLE μνλ‘ λ§λ¦
- notifyAll(): λκΈ°νκ³ μλ λͺ¨λ μ€λ λλ₯Ό κΉ¨μ°κ³ λͺ¨λ RUNNABLE μνλ‘ λ§λ¦
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyLabel extends JLabel {
int barSize = 0;
int maxBarSize;
MyLabel(int maxBarSize) {
this.maxBarSize = maxBarSize;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.MAGENTA);
int width =
(int)((double)getWidth()*barSize/maxBarSize);
if(width==0) return;
g.fillRect(0, 0, width, this.getHeight());
}
synchronized void fill() {
if(barSize==maxBarSize) {
try {
wait();
} catch(InterruptedException e) { return; }
}
barSize++;
repaint();
notify();
}
synchronized void consume() {
if(barSize==0) {
try {
wait();
} catch(InterruptedException e) { return; }
}
barSize--;
repaint();
notify();
}
}
class ConsumerThread extends Thread {
MyLabel bar;
ConsumerThread(MyLabel bar) {
this.bar = bar;
}
@Override
public void run() {
while(true) {
try {
sleep(200);
bar.consume();
} catch(InterruptedException e) { return; }
}
}
}
public class Thread05 extends JFrame {
private MyLabel bar = new MyLabel(100);
Thread05() {
super("Thread Exam 05");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(350, 200);
Container c = getContentPane();
c.setLayout(null);
bar.setBackground(Color.ORANGE);
bar.setOpaque(true);
bar.setLocation(20, 50);
bar.setSize(300, 20);
c.add(bar);
c.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
bar.fill();
}
});
setVisible(true);
c.setFocusable(true);
c.requestFocus();
ConsumerThread ct = new ConsumerThread(bar);
ct.start();
}
public static void main(String[] args) {
new Thread05();
}
}
- wait()-notify() μμ
728x90
λ°μν
'Development Study > Java' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Java] Lecture - Day 18 (1) | 2024.06.06 |
---|---|
[Java] Lecture - Day 17 (1) | 2024.06.06 |
[Java] Lecture - Day 15 (0) | 2024.04.26 |
[Java] Lecture - Day 14 (0) | 2024.04.05 |
[Java] Lecture - Day 13 (1) | 2024.03.30 |
Comments