2022-05-15-쓰레드와동기화
본문 바로가기
CS Study/JAVA

2022-05-15-쓰레드와동기화

by KyeongMin 2022. 5. 16.
728x90
반응형

01.쓰레드 그리고 동기화

  • 시간이 지나가면서 program 만드는 속도가 많이 줄어듦
    • 이전에 비해 많이 줄어듦
  • 이전에 1 ~ 10가지 기술로 개발을 해야했다면 전체를 다 알고 개발을 했음
    • 예를 들어 쓰레드라는 기술이 필요하다면 전부를 알아야했다 물론 전부를 알고 있으면 좋긴함
    • 요새는 위의 10가지 기술을 기반 기술이라고 한다면 이것을 비슷한 여러개를 하나로 묶음
      • 이를 프레임워크라는 용어로 쓰인다고 함, 요즘은 이런 프레임 워크가 많아져서 하나하나 구현할 필요가 없어지는 것
  • 요즘은 속도를 더 중요시하지는 않는다 얼마나 원하는 것을 구현하는가를 중요시 함

02.쓰레드 이해와 생성

  • 실행중인 프로그램을 프로세스라고 함
    • 그 프로세스에서 일이나 작업
  • java에서 main()역시 쓰레드이다.
  • 흐름을 만드는 주체, 최소단위를 말함
  • 멀티 쓰레드는?
    • 하나의 프로세스 안에 2개이상의 쓰레드가 있는 것
    Thread ct = Thread.currentThread();
    String name = ct.getName();//쓰레드의 이름을 받아옴
  • 쓰레드 과정
    • Runnable을 구현한 인스턴스 생성
    • Thread 인스턴스 생성
    • Start 메소드 호출
    Runnable task = () -> {
    	int n1 = 10;
        int n2 = 20;
        String name = Thread.currentThread().getName();
        System.out.println(name + " : " + (n1 + n2));
    }
    
    Thread t = new Thread(task);
    t.start();//쓰레드 생성 및 실행

03.둘 이상 쓰레드 생성

Runnable task1 = () -> {
    //로직1
}
Runnable task2 = () -> {
    //로직2
}
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task2);

class Task extends Thread{
    public void run(){
	}
}// 이것과 같이 클래스로도 가능하다 하지만 요새는 람다식이 잘되어 있어 람다식으로 한다.

03.1 Join()

  • 쓰레드의 종료를 기다린다.
  • 쓰는 것은 쓰레드가 완료된 후 결과를 출력하고 싶은 경우 쓰레드가 종료하기를 기다리기 위해 사용하는 것

04.쓰레드의 동기화

  • 싱글 쓰레드에서는 문제가 없음
  • 멀티쓰레드를 사용했을 경우 문제가 발생
    • 공유자원에 대한 문제가 발생
  • 쓰레드로 count++ 하는 로직 하나와 count--하는 로직을 만들었을때
    • 이상적으로 우리는 100번 씩 했다하면 0이 나와야한다고 생각한다.
    • 하지만 우리가 생각한것처럼 0이 나오지 않는다
    • 이것의 문제가 공유자원을 접근했을때 다른 쓰레드의 동작이 끝나지 않은상태에서 또다른 쓰레드가 공유자원을 가져와서 쓰기 때문에 문제가 발생하는것
  • 위의 문제를 방지하기위해서 공유자원을 다른 쓰레드가 쓰고 있을 때 쓰지 못하게 하는 것 이를 쓰레드의 동기화라고 한다.
    • 상호배제를 하는것이라고 생각하면 쉽다.

04.1 동기화는 어떻게 하나요?

  • synchronized를 선언해주면 됨
  • synchronized public void increment(){};
  • 동기화 블럭
  • synchronized (this){
    	count++;
    }

05.쓰레드를 생성하는 더 좋은 방법

  • 쓰레드 풀 모델
    • 쓰레드 생성과 소멸은 리소스 소모가 많음
    • 쓰레드 풀은 쓰레드를 재활용하기 위한 모델
    • 여러개 작업이 있는 경우 몇개의 쓰레드가 필요하는지? 이것을 선택하는것이 어려운 문제이다
      • 어떤 프로그램은 싱글쓰레드로 쓰는것이 오히려 성능면에서도 좋기에 적절히 써야한다.
ExecutorService exr = Executors.newSingleThreadExecutor();
exr.submit(task);// 여기서 task는 우리가 만드는 로직이고 쓰레드 풀에 작업 전달
exr.shudown();// 쓰레드 풀과 그 안에 있는 쓰레드 소멸

05.1쓰레드 풀의 유형

new SingleThreadExecutor;
new FixedThreadPool(3);//숫자만큼 쓰레드 생성유지
new CacheThreadPool; //작업의 수에 맞게 유동적으로 관리

06.Callable & Future

  • main() 쓰레드에 t1, t2가 있을때 각각의 쓰레드한테 t1은 1 ~ 50 , t2는 51 ~ 100 하라고 하는것
    • 이런것을 가르켜 워크 쓰레드라고 함
    • 단, 이렇게 하면 main()쓰레드가 취합해야한다 그렇기 때문에 때에 따라서 쓰레드가 연산 결과를 반환해야함
      • 이전의 쓰레드는 반환 값이 void라서 그렇게 안됨
  • before
  • public interface Runnable{
    	void run();
    }
  • after
  • Functional Interface public interface Callable<V>{
        V call() throws Exception;
    }
  • 실제 사용법
  • public static void main(String[] args) throws InterruptedException, ExecutionException{
    	Callable<Integer> task = () -> {
    		int sum=0;
    		for(int i=0; i<10; i++){
    			sum+=i;
    		}
    		return sum;
    	};
    
    	ExecutorService exr = Executors.newSingleThreadExecutor();
    	Future<Integer> fur = exr.submin(task);
    
    	Integer r = fur.get();//스레드의 반환 값 획득
    	System.out.print
    }

07.syncronized 대신하는 ReentrantLock

class MyClass{
    ReentrantLock criticObj = new ReetrantLock();
    void myMethod(int arg){
		criticObj.lock();
        //...
        criticObj.unlock();
    }
}
  • 권고
  • class MyClass{
        ReentrantLock criticObj = new ReetrantLock();
        void myMethod(int arg){
           criticObj.lock();
            try{
            //...
            }finally{
                criticObj.unlock();
            }
        }
    }

08.컬렉션 인스턴스 동기화

public static <T> Set<T> syncronizedSet (Set<T>s)
public static <T> List<T> syncronizedSet (List<T>list)
public static <K,V> Map<K,V> syncronizedSet (Map<K,V>m)
public static <T> Collection<T> syncronizedSet (Collection<T>c)
  • 사용
    • 중요한점 이렇게 하더라도 반복자를 써서 저장을 하면 그 반복자 자체를 동기화 해주는것이 아님
      • 그렇기 때문에 반복자 역시 동기화를 해줘야함
  • List<String> lst = Collections.syncronizedList(new ArrayList<String>());
  • before | 제대로 동기화 안됨
  • Runnable task = () -> {
        ListIterator<Integer> itr = lst.listIterator();
        while(itr.hasNext())
            itr.set(itr.next()+1);
    }
  • after | 제대로 동기화됨
  • Runnable task = () -> {
        syncronized(lst){
        ListIterator<Integer> itr = lst.listIterator();
        while(itr.hasNext())
            itr.set(itr.next()+1);
        }
    }

https://github.com/3DPIT/3dpit.github.io/blob/main/content/blog/Java/2022-05-15-%EC%93%B0%EB%A0%88%EB%93%9C%EC%99%80%EB%8F%99%EA%B8%B0%ED%99%94.md

 

GitHub - 3DPIT/3dpit.github.io

Contribute to 3DPIT/3dpit.github.io development by creating an account on GitHub.

github.com

 

728x90
반응형

'CS Study > JAVA' 카테고리의 다른 글

2022-05-24-자바-상속이란  (0) 2022.05.24
2022-05-21-자바와-코틀린의차이  (0) 2022.05.24
2022-04-23-자바-기초정리1  (0) 2022.04.24
2022-04-23-자바의-메모리-모델과-Object-클래스  (0) 2022.04.24
2021.10.05_java-static  (0) 2021.10.05

댓글