자바에서 멀티스레드를 사용할 때 크게 2가지 방법이 있다.
Thread 클래스를 상속받아 run() 메서드 오브라이드Runnable 인터페이스를 구현해 Thread 생성자에게 전달하지만 자바는 다중 상속을 지원하지 않기에 다른 클래스를 상속한 경우 Runnable 인터페이스를 구현해야 스레드로 동작시킬 수 있다.
Thread 상속 : 단일 상속Runnable 구현 : 다중 상속 가능class Bus extends Car implements Runnable {
@Override
public void run() {
System.out.println("버스가 달리고 있습니다.");
}
}
멀티스레드 환경에서는 Race Condition이 발생할 수 있습니다. 이를 해결하기 위해 synchronized 키워드 또는 Lock을 사용해 임계 구역을 보호해야 한다.
Race Condition?
두 개 이상의 스레드가 동시에 같은 객체를 수정하려고 하면 결과가 꼬임
synchronized (order) {
if (!order.isProcessed()) {
order.setProcessed(true);
System.out.println("Order " + order.id + " processed!");
}
}
Order 객체는 id, status (NEW, PROCESSING, COMPLETED, CANCELLED)를 가진다.OrderProcessor 인터페이스를 정의하고, process(Order order) 메소드를 갖는다.CreditCardOrderProcessor, PayPalOrderProcessor 같은 구현체가 존재한다.Order order = new Order(1001, "NEW");
OrderProcessor processor = new CreditCardOrderProcessor();
Thread t1 = new Thread(() -> processor.process(order));
Thread t2 = new Thread(() -> processor.process(order));
t1.start();
t2.start();
Order 1001 is processed by CreditCard.
interface OrderProcessor {
public void process(Order order);
}
public class test {
public static void main(String[] args) {
Order order = new Order(1001, "NEW");
OrderProcessor processor = new CreditCardOrderProcessor();
Thread t1 = new Thread(() -> processor.process(order));
Thread t2 = new Thread(() -> processor.process(order));
t1.start();
t2.start();
}
}
class CreditCardOrderProcessor implements OrderProcessor{
@Override
public void process(Order order) {
synchronized(order){
if(!order.isProcessed()){
System.out.println("Order" + order.id + " is processed by CreditCard");
order.setProcessed(true);
}
}
}
}
class PayPalOrderProcessor implements OrderProcessor{
@Override
public void process(Order order) {
synchronized(order){
if(!order.isProcessed()){
System.out.println("Order" + order.id + " is processed by PayPal");
order.setProcessed(true);
}
}
}
}
class Order{
int id;
String status;
private boolean processed = false;
public Order(int id, String status){
this.id = id;
this.status = status;
}
public boolean isProcessed(){
return processed;
}
public void setProcessed(boolean processed) {
this.processed = processed;
}
}