Java Thread
๐ฟ Thread LifeCycle
- New: Thread.start() ํ๋ฉด ์คํ๋จ
- Runnable: startํ๋ฉด runnable๋ก ๋ฐ๋
- Control์ด Thread Scheduler๋ก ๊ฐ์ ์คํ์ ๊ธฐ๋ค๋ฆผ
- Running: Scheduler๊ฐ ์คํ์ ์ํจ ์ํ
- Blocked
- Waiting for I/O resources
- Waiting for a monitor lock
- Waiting: ๋ค๋ฅธ Thread๊ฐ ํน์ action์ performํ๊ธธ ๊ธฐ๋ค๋ฆฌ๋ ์ํ
- Object.wait with no timeout
- Thread.join with no timeout
- ์๋ฅผ ๋ค์ด Object.wait()๋ฅผ ํน์ object์ ํธ์ถํ ํ ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ Object.notify or Object.notifyAll()๋ฅผ ๊ทธ Object์ ํธ์ถํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์ํ
- waiting์ด ๋๋๋ฉด Runnable๋ก ๋์๊ฐ
- Timed_Waiting: ๋ฐ์ ํจ์๋ฅผ ํธ์ถ ํด์ waiting ์ํ
- Thread.sleep
- Object.wait with timeout
- Thread.join with timeout
- Terminated: run()์ด ๋๋๋ฉด ์์์ ๋ฐ๋ฉํ๊ณ ์ข ๋ฃ
๐ฟ Thread ์์ฑ์
ํจ์ | ์ค๋ช |
---|---|
Thread() | ์ค๋ ๋ ์ด๋ฆ |
Thread(Runnable r) | ์ธํฐํ์ด์ค ๊ฐ์ฒด |
Thread(Runnable r, String s) | ์ธํฐํ์ด์ค ๊ฐ์ฒด์ ์ค๋ ๋ ์ด๋ฆ |
๐ฟ Thread Method
ํจ์ | ์ค๋ช |
---|---|
static void sleep(long msec) throws Interrupted Exception | msec์ ์ง์ ๋ ๋ฐ๋ฆฌ์ด ๋์ ๋๊ธฐ |
String getName() | ์ค๋ ๋์ ์ด๋ฆ์ s๋ก ์ค์ |
void setName(String s) | ์ค๋ ๋์ ์ด๋ฆ์ s๋ก ์ค์ |
void start() | ์ค๋ ๋๋ฅผ ์์ run() ๋ฉ์๋ ํธ์ถ |
int getPriority() | ์ค๋ ๋์ ์ฐ์ ์์๋ฅผ ๋ฐํ |
void setpriority(int p) | ์ค๋ ๋์ ์ฐ์ ์์๋ฅผ p๊ฐ์ผ๋ก |
boolean isAlive() | ์ค๋ ๋๊ฐ ์์๋์๊ณ ์์ง ๋๋์ง ์์์ผ๋ฉด true ๋๋ฌ์ผ๋ฉด false ๋ฐํ |
void join() throws InterruptedException | ์ค๋ ๋๊ฐ ๋๋ ๋ ๊น์ง ๋๊ธฐ |
void run() | ์ค๋ ๋๊ฐ ์คํํ ๋ถ๋ถ ๊ธฐ์ (์ค๋ฒ๋ผ์ด๋ฉ ์ฌ์ฉ) |
void suspend() | ์ค๋ ๋๊ฐ ์ผ์์ ์ง resume()์ ์ํด ๋ค์์์ ํ ์ ์๋ค. |
void resume() | ์ผ์ ์ ์ง๋ ์ค๋ ๋๋ฅผ ๋ค์ ์์. |
void yield() | ๋ค๋ฅธ ์ค๋ ๋์๊ฒ ์คํ ์ํ๋ฅผ ์๋ณดํ๊ณ ์์ ์ ์ค๋น ์ํ๋ก |
๐ฟ Thread ์์ฑ
extend Thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Test extends Thread {
int seq;
public Test(int seq) {
this.seq = seq;
}
public void run() {
System.out.println(this.seq+" thread start.");
try {
Thread.sleep(1000);
}catch(Exception e) {
}
System.out.println(this.seq+" thread end.");
}
public static void main(String[] args) {
for(int i=0; i<10; i++) {
Thread t = new Test(i);
t.start();
}
System.out.println("main end.");
}
}
output
1
2
3
4
5
6
7
8
9
0 thread start.
4 thread start.
6 thread start.
2 thread start.
main end.
3 thread start.
...
1 thread end.
5 thread end.
- ํน์ง
- test.start() ์คํ ์ test๊ฐ์ฒด์ run ๋ฉ์๋๊ฐ ์ํ
- ์ฐ๋ ๋๊ฐ ์ข ๋ฃ๋๊ธฐ ์ ์ main ๋ฉ์๋๊ฐ ์ข ๋ฃ
๐ฟ Join
์ฐ๋ ๋๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ฒ ํ๋ ๋ฉ์๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
ArrayList<Thread> threads = new ArrayList<Thread>();
for(int i=0; i<10; i++) {
Thread t = new Test(i);
t.start();
threads.add(t);
}
for(int i=0; i<threads.size(); i++) {
Thread t = threads.get(i);
try {
t.join();
}catch(Exception e) {
}
}
System.out.println("main end.");
}
output
1
2
3
4
5
6
0 thread start.
5 thread start.
2 thread start.
6 thread start.
...
main end.
- ํน์ง
- ๋ชจ๋ ์ฐ๋ ๋๊ฐ ์ข ๋ฃ๋ ํ์ main ๋ฉ์๋๋ฅผ ์ข ๋ฃ
๐ฟ Runnable
ํํ ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ
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
32
public class Test implements Runnable {
int seq;
public Test(int seq) {
this.seq = seq;
}
public void run() {
System.out.println(this.seq+" thread start.");
try {
Thread.sleep(1000);
}catch(Exception e) {
}
System.out.println(this.seq+" thread end.");
}
public static void main(String[] args) {
ArrayList<Thread> threads = new ArrayList<Thread>();
for(int i=0; i<10; i++) {
Thread t = new Thread(new Test(i));
t.start();
threads.add(t);
}
for(int i=0; i<threads.size(); i++) {
Thread t = threads.get(i);
try {
t.join();
}catch(Exception e) {
}
}
System.out.println("main end.");
}
}
- ํน์ง
- Thread t = new Thread(new Test(i));
๐ฟ Thread ์ฐ์ ์์
์ฐ์ ์์๋ผ๋ ์์ฑ(๋ฉค๋ฒ๋ณ์)์ ๊ฐ์ ๋ฐ๋ผ ์ฐ๋ ๋๊ฐ ์ป๋ ์คํ์๊ฐ์ด ๋ฌ๋ผ์ง
- ์ฐ๋ ๋๊ฐ ์ํํ๋ ์์ ์ ์ค์๋์ ๋ฐ๋ผ ์ฐ๋ ๋์ ์ฐ์ ์์๋ฅผ ์๋ก ๋ค๋ฅด๊ฒ ์ง์ ํ์ฌ ํน์ ์ฐ๋ ๋๊ฐ ๋ ๋ง์ ์์ ์๊ฐ์ ๊ฐ๋๋ก ํ ์ ์๋ค
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
32
33
34
35
36
37
38
39
class ThreadPriority {
public static void main(String args[]) {
A th1 = new A();
B th2 = new B();
th1.setPriority(4); // defalut ์ฐ์ ์์ 5
th2.setPriority(7);
System.out.println("Priority of th1(-): " + th1.getPriority());
System.out.println("Priority of th2(|): " + th2.getPriority());
th1.start();
th2.start();
}
}
class A extends Thread {
public void run() {
for(int i=0; i < 300; i++) {
System.out.print("-");
for(int x=0; x < 10000000; x++);
}
}
}
class B extends Thread {
public void run() {
for(int i=0; i < 300; i++) {
System.out.print("|");
for(int x=0; x < 10000000; x++);
}
}
}
์ฐ์ ์์๊ฐ ๋์ th2์ ์คํ์๊ฐ์ด th1์ ๋นํด ์๋นํ ๋์ด๋๋ค.
๐ฟ Main ์ฐ๋ ๋
๋ฉ์ธ์ด ์ํํ๋ ์ค๋ ๋ public static void main(String[] args)
- The main thread is created automatically when our program is started
Main Thread Controll
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class Test extends Thread {
public static void main(String[] args) {
// getting reference to Main thread
Thread t = Thread.currentThread();
// getting name of Main thread
System.out.println("Current thread: " + t.getName());
// changing the name of Main thread
t.setName("Geeks");
System.out.println("After name change: " + t.getName());
// getting priority of Main thread
System.out.println("Main thread priority: "+ t.getPriority());
// setting priority of Main thread to MAX(10)
t.setPriority(MAX_PRIORITY);
System.out.println("Main thread new priority: "+ t.getPriority());
for (int i = 0; i < 2; i++) {
System.out.println("Main thread");
}
// Main thread creating a child thread
ChildThread ct = new ChildThread();
// getting priority of child thread
// which will be inherited from Main thread
// as it is created by Main thread
System.out.println("Child thread priority: "+ ct.getPriority());
// setting priority of Main thread to MIN(1)
ct.setPriority(MIN_PRIORITY);
System.out.println("Child thread new priority: "+ ct.getPriority());
// starting child thread
ct.start();
}
}
// Child Thread class
class ChildThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 2; i++){
System.out.println("Child thread");
}
}
}
output
1
2
3
4
5
6
7
8
9
10
Current thread: main
After name change: Geeks
Main thread priority: 5
Main thread new priority: 10
Main thread
Main thread
Child thread priority: 10
Child thread new priority: 1
Child thread
Child thread
๋๊ธฐํ
Synchronized๋ฅผ ์ด์ฉํ ๋๊ธฐํ
๊ฐ์ฒด์ lock์ ๊ฑธ๊ณ ์ ํ ๋
1
2
3
4
5
synchronized(๊ฐ์ฒด์ ์ฐธ์กฐ๋ณ์){
//.....
}
method์ lock์ ๊ฑธ๊ณ ์ ํ ๋
1
2
3
4
5
public synchronized void calcSum(){
//.....
}
- ํจ์์ synchronized๋ฅผ ๊ฑธ๋ฉด ๊ทธ ํจ์๊ฐ ํฌํจ๋ ํด๋น ๊ฐ์ฒด(this)์ lock์ ๊ฑฐ๋๊ฒ
Example
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
32
33
34
35
36
37
class ThreadEx24 {
public static void main(String args[]) {
Runnable r = new A();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
class Account {
int balance = 1000;
public synchronized void withdraw(int money){ //synchronized ํค์๋๋ฅผ ๋ถ์ด๊ธฐ๋ง ํ๋ฉด ๊ฐ๋จํ ๋๊ธฐํ๊ฐ ๋๋ค.
if(balance >= money) {
try { Thread.sleep(1000);} catch(Exception e) {}
balance -= money;
}
} // withdraw
}
class A implements Runnable {
Account acc = new Account();
public void run() {
while(acc.balance > 0) {
// 100, 200, 300์ค์ ํ ๊ฐ์ ์์ผ๋ก ์ ํํด์ ์ถ๊ธ(withdraw)
int money = (int)(Math.random() * 3 + 1) * 100;
acc.withdraw(money);
System.out.println("balance:"+acc.balance);
}
} // run()
}
- Synchronized๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์์์น ๋ชปํ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค
DeadLock
์๊ณ์์ญ: ๋ ์ด์์ ์ฐ๋ ๋๊ฐ ๋์์ ์คํ๋ ๊ฒฝ์ฐ ์๊ธธ ์ ์๋ ๋์ ์ ๊ทผ ๋ฌธ์ ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ ์ฝ๋ ๋ธ๋ก(Critical Section)
- Thread1์ด A์ ์๊ณ์์ญ(test1)์ ์ง์
ํ ์๊ณ์์ญ์์ ํ์ถ ํ์ง ์์ ์ฑ B์ ์๊ณ์์ญ(test2)์ ์ง์
- B์ ์ง์ ํ ์ํฉ์์ A๋ Lock์ ํ๋ํด Blocked ์ํ
- Thread2๊ฐ ์๊ณ์์ญ(test1) ์ง์
ํ ์ํ์ด๋ฏ๋ก BLOCKED ๋จ
- Thread2๊ฐ test1์ ํตํด ObectA์ test2์ ์ง์ ํ๋ ค ํ์ง๋ง Lock์ด ํ๋ฆฌ์ง ์์์ผ๋ฉฐ BLOCKED
๊ฒฐ๊ณผ์ ์ผ๋ก 2๊ฐ์ Thread๊ฐ ์๋ก LOCK์ ํด์ ํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฏ๋ก ์์ํ BLOCKED ๋จ
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public class DeadLockTest {
@Test
public void runDeadLock() {
Shared s1 = new Shared();
Shared s2 = new Shared();
ExecutorService es = Executors.newFixedThreadPool(3);
Future<?> future1 = es.submit(new Task(s1, s2));
Future<?> future2 = es.submit(new Task(s2, s1));
es.shutdown();
try {
int awaitCnt = 0;
while (!es.awaitTermination(10, TimeUnit.SECONDS)) {
System.out.println("Not a terminate threads. ");
reportDeadLockThread();
awaitCnt++;
if ( awaitCnt > 3 && !future1.isCancelled() && !future2. isCancelled() ) {
// (4)
future1.cancel(true);
future2.cancel(true);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// (5)
private void reportDeadLockThread() {
ThreadMXBean bean = ManagementFactory.getThreadMXBean(); // Returns null if no threads are deadlocked.
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
for (ThreadInfo info : infos) {
String s = info.getThreadName();
System.out.println(String.format("DeadLocked Thread Name >>>> %s", s));
}
}
}
static class Shared {
// (1)
synchronized void test1(Shared s2) {
System.out.println("test1-begin");
ThreadUtil.sleep(1000);
// (2)
s2.test2(this);
System.out.println("test1-end");
}
// (3)
synchronized void test2(Shared s1) {
System.out.println("test2-begin");
ThreadUtil.sleep(1000);
// taking object lock of s1 enters
// into test1 method
s1.test1(this);
System.out.println("test2-end");
}
}
static class Task implements Runnable {
private Shared s1;
private Shared s2;
// constructor to initialize fields
Task(Shared s1, Shared s2) {
this.s1 = s1;
this.s2 = s2;
}
// run method to start a thread
@Override public void run() {
// taking object lock of s1 enters
// into test1 method
s1.test1(s2);
}
}
}
- runDeadLock ํจ์๋ฅผ ํตํด์ thread 1, thread 2๊ฐ ๊ฑฐ์ ๋์์ ์์
- ๊ฐ thread๋ test1() ํจ์์ ์คํ์ ์์ํ๋ค.
- this์ ๋๊ธฐํ ๋ธ๋ญ์ด ์์๋๋ฉด์ ์์ฐ์ค๋ Lock๊ฐ์ฒด๋ฅผ ๊ณต์ ํ๋ test2()๋ Lock์ด ๊ฑธ๋ฆฐ๋ค.
- ๋ค๋ฅธ๊ฐ์ฒด ์ฆ s2๊ฐ์ฒด์ test2() ํจ์๋ฅผ ํธ์ถํ๋ค.
- ๋ค๋ฅธ thread๋ ๋์์ ์ถ๋ฐ ํ๊ธฐ ๋๋ฌธ์ ์ด ํจ์๋ ์ด๋ฏธ Lock์ด ๊ฑธ๋ ค์ ์ด ํธ์ถ thread๋ ์ด ์ง์ ์์ BLOCKED ๋๋ค.
- test2() ํจ์๊ฐ synchronized๊ฐ ์ ์ธ๋์ง ์์๋ค๋ฉด Thread2์์ test1์ ํตํด test2๋ฅผ ์คํ์ฌ๊ณ Lock์ด ํ๋ ค s1 ๊ฐ์ฒด๋ ์ ์ ์คํ ๋์์ ๊ฒ์ด๋ค.
- ํด๋น thread๋ฅผ cancel์ ํ๋ค. ๊ทธ๋ฌ๋ ์๋ฌด ํจ๊ณผ๊ฐ ์๋ค.
- ์๋ฌต์ ์ธ Lock์ด BLOCKED ๋๋ฉด ์ค๋จ์ํฌ ๋ฐฉ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.