멀티스레드를 효과적으로 사용하면 프로그램 성능을 크게 향상시킬 수 있지만, 여러 스레드가 동시에 데이터를 공유하고 수정할 때 발생하는 동기화 문제를 해결하지 않으면 데이터의 안정성과 신뢰성을 보장할 수 없습니다.
자바에서는 이러한 문제를 해결하기 위해 synchronized
키워드를 제공하여 스레드 간 동기화를 가능하게 합니다.
멀티스레드 환경에서 공유 데이터를 안전하게 관리하려면 스레드 간 동기화가 필수적입니다. 예를 들어, 여러 스레드가 동일한 데이터에 접근하고 수정할 때 동기화가 이루어지지 않으면 데이터의 일관성이 깨질 수 있습니다. 이러한 문제를 해결하기 위해 자바는 synchronized
키워드를 제공합니다.
synchronized
키워드synchronized
키워드는 여러 스레드가 하나의 자원을 사용하고자 할 때, 현재 자원을 사용 중인 스레드를 제외하고 나머지 스레드의 접근을 막는 역할을 합니다. 이는 데이터의 일관성을 유지하고 스레드 간의 경합 조건을 방지하는 데 유용합니다. 하지만, synchronized
키워드를 남용하면 오히려 프로그램의 성능 저하를 초래할 수 있으므로 적절한 사용이 중요합니다.
synchronized
public synchronized void method() {
// 코드
}
메서드에 synchronized
키워드를 사용하면 해당 메서드를 실행하는 동안 다른 스레드가 이 메서드에 접근하지 못하게 합니다.
private final Object lock = new Object();
public void exampleMethod() {
synchronized(lock) {
// 코드
}
}
동기화 블록을 사용하여 특정 객체를 기준으로 동기화할 수 있습니다. 이 방법은 메서드 전체가 아닌 특정 부분만 동기화할 때 유용합니다.
public class ThreadSynchronizedTest {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.setName("t1-Thread");
t2.setName("t2-Thread");
t1.start();
t2.start();
}
}
class Account {
int balance = 1000;
public void withDraw(int money) {
if (balance >= money) {
try {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " 출금 금액 ->> " + money);
Thread.sleep(1000);
balance -= money;
System.out.println(thread.getName() + " balance: " + balance);
} catch (Exception e) {}
}
}
}
class Task implements Runnable {
Account acc = new Account();
@Override
public void run() {
while (acc.balance > 0) {
int money = (int) (Math.random() * 3 + 1) * 100;
acc.withDraw(money);
}
}
}
위 예제에서 두 스레드 t1
과 t2
가 동시에 balance
를 감소시키는 작업을 수행합니다. 그러나 동기화가 이루어지지 않아 balance
값이 마이너스가 되는 문제가 발생할 수 있습니다.
public class ThreadSynchronizedTest {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.setName("t1-Thread");
t2.setName("t2-Thread");
t1.start();
t2.start();
}
}
class Account {
int balance = 1000;
public synchronized void withDraw(int money) {
if (balance >= money) {
try {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " 출금 금액 ->> " + money);
Thread.sleep(1000);
balance -= money;
System.out.println(thread.getName() + " balance: " + balance);
} catch (Exception e) {}
}
}
}
class Task implements Runnable {
Account acc = new Account();
@Override
public void run() {
while (acc.balance > 0) {
int money = (int) (Math.random() * 3 + 1) * 100;
acc.withDraw(money);
}
}
}
동기화 키워드를 사용하여 withDraw
메서드를 동기화하면, 하나의 스레드가 이 메서드를 실행하는 동안 다른 스레드는 접근할 수 없습니다. 이를 통해 balance
값의 일관성을 유지할 수 있습니다.
멀티스레드 환경에서 동기화는 필수적인 요소입니다. 자바의 synchronized
키워드를 사용하여 스레드 간의 경합을 방지하고 데이터의 일관성을 유지할 수 있습니다.
하지만, synchronized
키워드의 남용은 성능 저하를 초래할 수 있으므로, 적재적소에 사용해야 한다는 특징이 있습니다. 때문에 데이터의 일관성을 꼭 보장해야할 필요가 없다면 사용하지 않는 것이 좋을때도 있습니다.