원자적 연산
- long과 double을 제외한 원시 타입 값 할당(읽고, 쓰기)
- long과 double은 내부적으로 32비트씩 잘라서 연산을 진행하므로 원자적 연산이 아니다.
- 이는 volatile 키워드를 변수 선언 시에 붙여줌으로써 해결할 수 있다.
public class AtomicOperations {
public static void main(String[] args) {
Metrics metrics = new Metrics();
BusinessLogic businessLogicThread1 = new BusinessLogic(metrics);
BusinessLogic businessLogicThread2 = new BusinessLogic(metrics);
MetricsPrinter metricsPrinter = new MetricsPrinter(metrics);
businessLogicThread1.start();
businessLogicThread2.start();
metricsPrinter.start();
}
public static class MetricsPrinter extends Thread{
private Metrics metrics;
public MetricsPrinter(Metrics metrics) {
this.metrics = metrics;
}
@Override
public void run() {
while(true){
try{
Thread.sleep(100);
}catch (InterruptedException e){
}
double currentAverage = metrics.getAverage();
System.out.println("Current Average is "+currentAverage);
}
}
}
public static class BusinessLogic extends Thread {
private Metrics metrics;
private Random random = new Random();
public BusinessLogic(Metrics metrics) {
this.metrics = metrics;
}
@Override
public void run() {
while(true){
long start = System.currentTimeMillis();
try{
Thread.sleep(random.nextInt(10));
}catch (InterruptedException e){
}
long end = System.currentTimeMillis();
metrics.addSample(end-start);
}
}
}
public static class Metrics {
private long count = 0;
private volatile double average = 0.0;
//메소드 내용 자체가 원자적 연산이 아니므로 synchronized 붙여준다.
public synchronized void addSample(long sample){
double currentSum = average * count;
count++;
average = (currentSum + sample)/count;
}
//double이므로 volatile을 붙여 원자적 연산이 진행되도록 한다.
public double getAverage() {
return average;
}
}
}
Deadlock
public static void main(String[] args) {
Intersection intersection = new Intersection();
Thread trainAThread = new Thread(new TrainA(intersection));
Thread trainBThread = new Thread(new TrainB(intersection));
trainAThread.start();
trainBThread.start();
}
public static class TrainA implements Runnable {
private Intersection intersection;
private Random random = new Random();
public TrainA(Intersection intersection) {
this.intersection = intersection;
}
@Override
public void run() {
while (true) {
long sleepingTime = random.nextInt(5);
try {
Thread.sleep(sleepingTime);
} catch (InterruptedException e) {
}
intersection.takeRoadA();
}
}
}
public static class TrainB implements Runnable {
private Intersection intersection;
private Random random = new Random();
public TrainB(Intersection intersection) {
this.intersection = intersection;
}
@Override
public void run() {
while (true) {
long sleepingTime = random.nextInt(5);
try {
Thread.sleep(sleepingTime);
} catch (InterruptedException e) {
}
intersection.takeRoadB();
}
}
}
public static class Intersection {
private Object roadA = new Object();
private Object roadB = new Object();
public void takeRoadA() {
synchronized (roadA) {
System.out.println("Road A is locked by thread " + Thread.currentThread().getName());
synchronized (roadB) {
System.out.println("Train is passing through road A");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
public void takeRoadB() {
synchronized (roadB) {
System.out.println("Road B is locked by thread " + Thread.currentThread().getName());
synchronized (roadA) {
System.out.println("Train is passing through road B");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
}
데드락 해결법
- 가장 간단한 방법은 순환 대기를 예방하는 것으로, 동일한 순서로 공유 리소스를 잠그고, 모든 코드에 해당 순서를 유지하면 된다.
- 아래와 같이 하면 데드락이 발생하지 않는다. 이때 언락의 순서는 상관없다.
public void takeRoadA() {
synchronized (roadA) {
System.out.println("Road A is locked by thread " + Thread.currentThread().getName());
synchronized (roadB) {
System.out.println("Train is passing through road A");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
public void takeRoadB() {
synchronized (roadA) {
System.out.println("Road B is locked by thread " + Thread.currentThread().getName());
synchronized (roadB) {
System.out.println("Train is passing through road B");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
'JAVA > 멀티스레딩' 카테고리의 다른 글
| 스레드간 통신 (0) | 2024.08.30 |
|---|---|
| 락킹 심화 (0) | 2024.08.29 |
| 멀티 스레드 주의 사항(병행성 문제) (0) | 2024.08.29 |
| Thread Pooling (0) | 2024.08.28 |
| 스레드 조정 (0) | 2024.08.28 |