본문 바로가기

JAVA공부(이것이 자바다)

스레드

멀티스레드 사용이유

 

작업을 동시에 해서 더 빠르게 처리하기 위함

 

스레드 정의 방법 4개

//Runnable을 상속받아 run 메소드를 재정의
class BeepPrintImpl implements Runnable {

	@Override
	public void run() {
		for(int i=0; i<5; i++) {
			System.out.println("띵");
			try {
				Thread.sleep(400);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

//Runnable객체를 상속받은 클래스의 객체를 생성해서 사용할 준비!!
BeepPrintImpl thread = new BeepPrintImpl();
thread.start();

	public class BeepPrintExample {
    
    // 클래스의 지역변수로 선언
	static Runnable beepPrintImpl = new Runnable() {

		@Override
		public void run() {
			for(int i=0; i<5; i++) {
				System.out.println("띵");
				try {
					Thread.sleep(400);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	};
    }

//Runnable인터페이스를 익명객체를 만들어 구현
Runnable beepPrintImpl = new Runnable() {

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            System.out.println("띵");
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
};

//이게 자주쓰는 방법인데 thread는 Runnable을 상속받고 있으므로 run()추상메소드만 재정의해서 구현한다.
Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            System.out.println("띵");
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
});
//스레드 시작
thread.start();

 

 

스레드 이름

메인스레드는 main()이라는 이름을 가지고 있고 작업스레드는 지정해주지 않으면 자동적으로 Thread-n이라고 설정해준다. 스레드의 이름은 setName()으로 지정할 수 있다 스레드의 이름은 현재 어떤 스레드가 실행하고 있는지 조사할 목적으로 주로 사용된다.

//Runnable을 통해서 구현했을 때
Thread thread = Thread.currentThread();//현재 실행중인 스레드를 받아옴
System.out.println(thread.getName());//그 스레드의 이름

//Thread로만 상속 받아서 구현햇을때
thread.getName();//딱 이것만 하면 땡~

스레드 이름 설정

thread.setName("이건내가만든쓰레드란다");

스레드 상태

sleep()

sleep은 실행대기로 가는 시간이 있어서 정확한 시간에 끝나지 않는다.

join()

다른 스레드가 종료될때까지 기다렸다가 실행을 해야하는 경우

-> 이게 없으면 main스레드가 죽으면 자식 스레드가 죽는다. 자식스레드가 원활히 끝날때까지 기다려주는 역할

wait()

스레드를 일시정지 상태로 만든다.

interrupt()

스레드를 실행대기 혹은 종료상태로 만든다.

-->예외 처리는 while문 바깥에서 해야한다. 무한히 실행 될 수 도 있기때문이다.

try{
	while(true){
    	thread.interrupt();
    }
 }catch(InterruptedException e){
 
 ]

notify() / notifyAll()

공유객체에서 두 스레드가 작업하고 있을때 하나는 일시정지하고 하나는 실행한다. 일시정지 중인 스레드에게 이제 실행될 시간이라고 알려줌 그리고 본인은 wait를 통해 cpu의 점유를 해제한다.

yield()

다른 스레드에게 실행 순서를 양보함 - > 무의미한 반복과정을 없애서 프로그램성능을 향상시킨다.

 

 

스레드 동기화

스레드가 공유하는 객체를 동시에 사용하게 되면 overwrite가 발생해서 값을 사용할때 잘못된 값을 사용하게 되거나 삽입시 오류가 발생할수있다.

그래서 메소드나 블록에 synchronized 키워드를 사용하여 한 스레드가 사용하고 있을때 다른 스레드가 접근하지 못하게 한다.  단. 되도록 공유객체 같은 걸 쓰지 않고 스레드 각각의 작업을 수행하도록해야한다.

동기화 메소드

public synchronized void method(){

}

동기화 블록

synchronized(this){

}

 

스레드의 안전 종료

stop()이라는 함수를 통해서 종료할 수 있지만 강제 종료이기 때문에 불안정한 종료임 그래서 setStop()이라는 메소드를 오버라이딩해서 종료과정을 정의해준다.

public void setStop(boolean stop){
	this.stop = stop;
    
  }

 

 

 

 

데몬스레드

join이랑 비슷한 것 같음 setDaemon(true)해놓으면 보조 스레드가 끝나면 메인 스레드가 종료된다.

 

스레드 풀

스레드의 갯수가 많아지면 성능이 떨어지게 된다. 이를 방지하기 위해서 스레드풀을 놓고 한번에 수행할수 있는 스레드의 수를 제한한다. 아래와 같은 함수를 통해 스레드 풀을 생성한다 코어수는 한번에실행할수 있는 스레드 수이다.

newFixedThreadPool(코어수)

스레드 풀 종료

shutdown()

현재 실행중인 스레드 , 작업큐의 스레드를 모두 처리한 뒤 종료

shutdownNow()

강제 종료하고 미처리된 작업큐의 스레드를 반환한다.

 

작업 생성과 처리 요청

-execute() 스레드의 작업을 작업큐에 저장한다

스레드의 run()에는 리턴 값이 없다! -> call()로 해결!!

-submit()를 통해 Collable인터페이스를 재정의 해서 call()함수를 불러 와 Future<T>객체를 통해 call()함수가 리턴한 값을 읽어 올 수 있다.

 

 

컬렉션 자료구조

컬렉션

자료구조를 바탕으로 한 객체들을 추가, 삭제, 검색할 수 있는 인터페이스와 클래스 도구들이다.

 

List<>

 객체 추가

boolean add(E e) - 주어진 객체를 맨끝에 추가

void add(int index, E element) - 인덱스에 객체 추가

set(int index, E element) - 인덱스의 객체를 새로운놈으로 바꿈

객체검색

boolean contains(object o) -인덱스에 저장된 객체리턴

E get(int index) - 인덱스에 저장된 객체리턴

isEmpty() - 컬렉션이 비어있는지 조사

int size() - 저장된 갯수 리턴

 

객체 삭제

void clear()-컬렉션 전부 날림

E remove(int index)-인덱스에 저장된 객체삭제

boolean remove(Object o) - 주어진 객체 삭제

 

ArrayList<>()

객체 제거시 인덱스를 하나씩 당겨오는 연산을 진행하고 인덱스 위치에 삽입시 하나씩 밀어내는 연산을 진행한다. 순서대로 저장한다. 단 멀티 스레드에서 동시 참조시 overwrite될 수 있다. 원하는 결과를 가져 오지 못할 수 있다. 검색이 빠르다.

List<E> list = new ArrayList<E>();

 

 

Vector<>()

동기화된 메소드로 구성되어있다. 멀티스레드가 Vector() 메소드로 실행 할 수없다. 그래서 멀티스레드 환경에서 안전하게 사용할 수있다 검색이 빠르다

List<E> list = new Vector<E>();

LinkedList<>()

앞뒤의 객체의 링크를 가지고 잇는 형태의 블럭들이 줄지어 있다고 보면된다. 삽입과 삭제가 빈번한 곳에서 ArrayList보다 성능이 좋다. 인덱스를 뒤로 미는 과정을 거치지 않기 때문이다. 단. 검색이 느리다 링크를 타고타고 가서 찾아 봐야하기때문이다.

List<E> list = new LinkedList<E>();

 

 

 

 

 

'JAVA공부(이것이 자바다)' 카테고리의 다른 글

스트림  (2) 2023.06.13
컬렉션 자료구조  (0) 2023.06.12
java.base 이어서  (0) 2023.06.08
java.base 모듈  (2) 2023.06.07
중첩클래스 이어서  (0) 2023.06.05