Java Thread

Gunjoo Ahn·2022년 8월 25일
0

Java Thread

Java에서 thread를 만드는 방법은 두 가지이다.

  1. Runnable Interface
  2. Thread Class

두 방식 모두 Thread 클래스 인스턴스를 생성하여 start() 메소드를 실행해야 실제 thread가 실행되는 것이다.

Runnable Interface

public class Sample implements Runnable {
	@Override
    public void run(){
    	...
    }
}

void somewhere(){
	// Use class implements Runnable
	Thread thread = new Thread(new Sample());
	thread.start();

	// Use lambda
	Thread lambdaThread = new Thread(() -> {...});
	lambdaThread.start();
}

Runnable 인터페이스를 이용하여 thread를 실행할 수 있다. 어떤 클래스든 인터페이스를 구현하기만 하면 언제든지 Thread에 주입하여 새로운 thread에서 실행할 수 있다.

Thread Class

@Data
public class Sample extends Thread {
	@Override
    public void run(){
    	...
    }
}

void somewhere(){
	Sample thread = new Sample();
    // Thread를 상속받았기에 바로 해당 인스턴스의 start 메소드 call
    thread.start();
}

Thread 클래스도 Runnable 인터페이스를 상속받고 있다. 따라서 Thread 클래스를 상속받아 thread를 실행할 수 있는데, Thread 클래스를 상속받아 구현하는 것은 다른 클래스를 상속받아 사용할 수 없기에 권장하지 않는다.

synchronized

Multi thread를 다루다 보면, thread들이 동시에 하나의 리소스에 접근하는 경우가 있다. C++에서는 mutex lock 같은 것으로 제어한다면, Java에서는 synchronized 키워드를 사용한다.

메소드나, 블럭을 생성해서 synchronized 키워드를 사용하여 리소스 접근을 제한할 수 있다.

// 아래 두 메소드는 같은 의미의 코드이다
public synchronized void example() {
	//Do something
}

public void example() {
	synchronized(this) {
		//Do something
	}
}

// 또는 위의 this대신 다른 object를 명시해서 해당 object에 lock을 걸 수도 있다
public void example(){
	synchronized(object){
    	//Do something
    }
}

static인 경우 살짝 차이가 있는데, 위와 같이 인스턴스가 아닌 클래스 자체에 lock을 건다.

하지만 synchronized 키워드는 성능 저하가 큰 단점이다. 그리고 static과 인스턴스 사이의 lock은 대상이 달라 디버깅이 어려워질 여지가 있다.

Lock-free

성능이 좋지 않은 synchronized 대신에 무엇을 쓰면 좋을까? Lock-free가 대안 중 하나이다.

Lock-free - A data structure provides lock-freedom if, at any time, at least one thread can proceed

즉 최소한 한 스레드는 항상 작업을 진행할 수 있다면 lock-free이다. Java에서 CAS(compare-and-swap, Non-blocking 으로 동작)을 통하여 lock-free를 구현할 수 있다.

Java atimic 패키지를 통하여 CAS를 사용할 수 있으며, Java concurrent 패키지의 클래스 대부분의 구현에 atomic 패키지의 클래스가 사용되었다.

결론

멀티 스레드 환경에서 성능 이슈가 있을 수 있으니, 따로 synchronized 키워드로 직접 컨트롤하지말고 new로 인스턴스를 새로 만들어서 해결하거나 Concurrent를 지원하는 패키지를 사용하자는 것이다.

참고

Lock-Freedom의 3가지 수준

Wait-Free
항상 어떤 스레드도 Wait을 하지 않고 모든 쓰레드가 실행 중이며, 즉 바운더리가 있는 CPU 사이클 내에 어떤 작업이 완료될 것이라고 보장된다.

Lock-Free
항상 적어도 하나의 쓰레드가 실행 중임을 보장받는다. 모든 Wait-Free는 Lock-Free이지만 반대는 성립하지않는다.

Obstruction-Free
가장 약한 정의로 적어도 하나의 쓰레드가 언젠가는 방해받지 않고 고립된 상태로 실행될 것이라 보장한다.

Reference

https://coding-start.tistory.com/68
https://reference-m1.tistory.com/87
https://tourspace.tistory.com/54
https://tourspace.tistory.com/55
https://effectivesquid.tistory.com/62
https://www.baeldung.com/lock-free-programming
https://narakit.tistory.com/194

profile
Backend Developer

0개의 댓글