잘못된 내용이 있다면 댓글로 알려주시면 감사하겠습니다. 🙇🏻♀️
TCB(Thread Control Block)
와 스택
을 가집니다.Blocking
되면 스레드의 실행 위치, 레지스터 값 등등은 TCB 문맥에 백업되기 때문에 스레드가 Blocking
상태에서 다시 Running
상태가 되더라도 안전하게 재실행될 수 있습니다.지역변수
를 두 스레드가 동시에 바꿔도 데이터가 깨지지 않습니다.race condition
문제가 발생할 수 있습니다.race condition
이 있습니다.producer consumer process
가 존재할 때를 예시로 들어보겠습니다.R1 = counter;
R1 = R1 + 1;
counter = R1;
Consumer
R2 = counter;
R2 = R2 - 1;
counter = R2;
count
에 값을 저장하냐에 따라 결과가 5 또는 6으로 달라지는 것을 확인할 수 있습니다.상호배제
(각 스레드는 공유 자원의 손상을 방지하기 위해 혼자서만 공유자원을 사용해야 함, 즉 어떤 스레드가 임계 영역
(공유 자원(공유 데이터, 공동으로 사용하는 I/O 디바이스들)를 읽거나 쓰는 코드영역)을 실행하고 있는 도중 다른 스레드가 동일한 임계 영역을 실행하게 해서는 안 됨) 하여야 합니다.synchronized
키워드를 사용해서 처리할 수 있습니다.다음과 같은 두 가지의 방법으로 동기화를 할 수 있습니다.
public class Main {
private String mHero;
public static void main(String[] agrs) {
Main main1 = new Main();
Main main2 = new Main();
System.out.println("Test start!");
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
main1.batman();}
}).start();
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
main2.batman();
}
}).start();
System.out.println("Test end!");
}
public synchronized void batman() {
mHero= "batman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("batman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void superman() {
mHero = "superman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("superman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
synchronized
키워드가 없는 다른 메서드를 호출해도 "synchronization broken"가 출력되지 않습니다.public class Main {
private String mHero;
public static void main(String[] agrs) {
Main main = new Main();
System.out.println("Test start!");
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
main.superman();}
}).start();
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
main.superman();
}
}).start();
System.out.println("Test end!");
}
public synchronized void batman() {
mHero= "batman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("batman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void superman() {
mHero = "superman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("superman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
static
키워드와 함께 사용한다면 클래스에 lock 합니다.public class Main {
private static String mHero;
public static void main(String[] agrs) {
System.out.println("Test start!");
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
Main.batman();}
}).start();
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
Main.batman();
}
}).start();
System.out.println("Test end!");
}
public static synchronized void batman() {
mHero= "batman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("batman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void superman() {
mHero = "superman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("superman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
synchrozied
키워드가 없는 클래스 내 static 메서드를 호출해도 실행 결과 "synchronization broken"은 출력되지 않습니다.public class Main {
private static String mHero;
public static void main(String[] agrs) {
System.out.println("Test start!");
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
Main.superman();}
}).start();
new Thread(() -> {
for (int i = 0; i<1000000; i++) {
Main.superman();
}
}).start();
System.out.println("Test end!");
}
public static synchronized void batman() {
mHero= "batman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("batman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void superman() {
mHero = "superman";
try {
long sleep = (long) (Math.random()*100);
Thread.sleep(sleep);
if ("superman".equals(mHero) == false) {
System.out.println("synchronization broken");
}
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
public class Main {
private Map<String, String> map1 = new HashMap<>();
private Map<String, String> map2 = new HashMap<>();
public static void main(String[] agrs) {
Main main1 = new Main();
System.out.println("Test start!");
new Thread(() -> {
for (int i = 0; i < 1; i++) {
main1.batman("asdf");
}
}).start();
new Thread(() -> {
for (int i = 0; i < 1; i++) {
main1.superman("asdfa");
}
}).start();
System.out.println("Test end!");
}
public void batman(String s) {
synchronized (map1){
map1.put("s", s);
}
}
public void superman(String s) {
synchronized (map2) {
map2.put("sb", s);
}
}
}
static
static
은 java에서 메서드, 필드 등에 붙일 수 있는 키워드입니다.static
은 스레드끼리 공유되는 자원으로, 클래스당 하나만 생성됩니다.- jvm 내에서
static
은heap
영역이 아닌 클래스 코드가 저장되는static
공간에 메모리가 할당됩니다.static
공간은 GC가 관리하지 않는 영역이기 때문에 프로그램 종료 시 까지 할당받은 메모리가 유지됩니다.
참고로 jvm 내에heap
영역은 클래스를 new 해서 인스턴스를 생성할 경우 사용되는 영역입니다. 이 영역은 GC 가 수시로 관리합니다.
https://ooeunz.tistory.com/110
https://yeonyeon.tistory.com/113
https://tourspace.tistory.com/54?category=788398
https://ohgyun.com/5