스레드(Thread)
스레드란?
- 여러 가지 일을 동시에 진행하는 것처럼 보이게 할 수 있는 것.
- 여러 스택이 아주 빠르게 번갈아 실행되기 때문에 여러 스택이 동시에 실행되는 것처럼 보인다.
- 스레드는 JVM 스레드 스케줄러가 실행시킬 스레드를 선택했다가 다른 스레드에 기회를 주는 과정을 반복함에 따라 실행 가능한 상태와 실행중인 상태 사이를 반복한다.
스레드 사용 방법
- 1. Runnable 객체(스레드에서 할 작업)를 만든다.
: Runnable은 인터페이스이다. 스레드에서 할 작업은 Runnable의 run 메소드를 오버라이딩 해서 만든다.
- 2. Thread 객체를 만들고 그 객체에 Runnable 객체를 전달한다.
: 새로운 Runnable 객체를 Thread 생성자에 전달한다.
public class test {
public static void main(String[] args){
Runnable threadRun = new myRunnable();
Thread myThread = new Thread(threadRun);
myThread.start();
System.out.println("메인 실행");
}
}
class myRunnable implements Runnable{
public void run(){
go();
}
public void go(){
test();
}
public void test(){
System.out.println("스레드 실행!");
}
}
- Thread 객체는 재사용이 불가능하다. run 메소드가 일단 종료되고 나면 사망 상태(dead state)가 된다. 사망 상태의 스레드는 run 메소드의 실행이 끝나 있는 상태이며, 절대로 재시작될 수 없다.
스레드 스케줄러
- 스레드 스케줄러는 어느 스레드가 실행되어야 하는지, 얼마나 오랫동안 실행되어야 하는지 등을 결정한다.
- 스케줄러는 사용자 마음대로 제어할 수 없다. 스케줄링과 관련하여 어느 것도 확언할 수 없다.
- 스케줄러가 어떤 특별한 방식으로 작동할 것을 가정하고 프로그램을 만들면 안 된다.
public class test {
public static void main(String[] args){
Runnable threadRun = new myRunnable();
Thread myThread1 = new Thread(threadRun);
Thread myThread2 = new Thread(threadRun);
myThread1.start();
myThread2.start();
System.out.println("메인 실행");
}
}
class myRunnable implements Runnable{
public void run(){
go();
}
public void go(){
test();
}
public void test(){
for(int i=0;i<5;i++)
{
System.out.println(Thread.currentThread().getName()+" 실행!" );
try {
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
스레드 락, 동기화
- 어떤 메소드를 한 번에 한 스레드만 접근할 수 있게 하고 싶으면 synchroized 키워드를 이용하여 락을 건다.
- synchronized 키워드가 있는 메소드에 한 스레드가 접근하면, 다른 스레드는 해당 메소드에 접근할 수 없다.
public class test {
public static void main(String[] args){
Runnable threadRun = new myRunnable();
Thread myThread1 = new Thread(threadRun);
Thread myThread2 = new Thread(threadRun);
myThread1.start();
myThread2.start();
System.out.println("메인 실행");
}
}
class myRunnable implements Runnable{
public void run(){
go();
}
public void go(){
test();
}
public synchronized void test(){
for(int i=0;i<5;i++)
{
System.out.println(Thread.currentThread().getName()+" 실행!" );
try {
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
스레드 동기화 주의 사항
- 스레드 사용 시 전부 동기화 하면 안전할 수 있다고 생각하지만, 하지 않는것이 좋다.
많은 동기화는 성능을 저하시킨다.
- 동기화가 꼭 필요한 부분에 synchroized 키워드를 이용하여 메소드 안의 특정한 부분만 동기화 시킨다.
class myRunnable implements Runnable{
public void run(){
go();
}
public void go(){
test();
}
public synchronized void test(){
for(int i=0;i<5;i++)
{
// 메소드 안 synchroized 이용 동기화
synchronized (this) {
System.out.println(Thread.currentThread().getName()+" 실행!" );
try {
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
- 정적 메소드나 정적 변수는 클래스 자체의 락을 사용한다. 즉, 인스턴스 락과 클래스 락이 따로 존재한다.
인스턴스가 3개 생성되었다면, 클래스 락을 포함해 총 4개의 락이 존재하는 것이다.
- 스레드 우선순위는 존재하지만, 스레드 스케줄링을 보장할 수는 없다. 성능에 영향을 주기 위한 용도로만 사용하고, 프로그램이 제대로 작동되기 위한 용도로 우선순위를 사용하는 일은 절대 없어야 한다.
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
[JAVA] 정적 메소드(Static Method) & 정적 변수(Static Variable) (0) | 2021.02.04 |
---|---|
[JAVA] String, StringBuilder, StringBuffer (0) | 2021.01.20 |
[JAVA] 예외 처리 (0) | 2021.01.20 |
[JAVA] 인터페이스(Interface) (0) | 2021.01.20 |
[JAVA] 추상 클래스(Abstract Class) & 추상 메소드(Abstract Method) (0) | 2021.01.20 |
댓글