자바 동시성 및 멀티 스레딩 (3) : 스레드 풀, 모닝콜 대기

첫째, 대기 웨이크 업 (wake-up)

1 개 스레드 간의 통신

개념 : 동일한 리소스에 작업을 여러 스레드, 그 작업 (스레드 작업은) 동일하게 취급되지 않습니다.
예를 들어 스레드가 스레드 B 롤빵위한 빵을 생성하는 데 사용되는, 빵이 동일한 자원 스레드 A 및 스레드 B의 처리 동작하는 것으로 이해 될 수 있으며, 그 스레드 A 및 스레드 B 사이 생산 및 소비이고 스레드 통신 문제가있다.
그림 삽입 설명 여기
스레드 간의 핸들 통신 이유는 (1) :
여러 스레드가 동시에 실행 우리가 작업을 완료하기 위해 함께 작업해야하는 경우 여러 스레드, 기본 CPU가 무작위로 스레드를 전환하고, 우리가 원하는 그들을 법의 구현을 가지고, 너무 많은 스레드 사이의 통신의 일부 조정이 필요합니다 우리가 상호 운용 가능한 멀티 스레드 데이터를 달성 할 수 있도록 순서를.
통신 스레드 간의 자원의 효과적인 사용을 보장하는 방법 (2) :
동일한 데이터를 조작하고, 여러 스레드, (첫째 효율성) 같은 공유 변수에 대한 회피 경쟁을 . 즉, 우리는 자원의 효과적인 사용에 의해 확인 각 스레드를 확인해야합니다. 그리고이 수단입니다 - 웨이크 업 메커니즘에 대한 대기 .

(2), 웨이크 업 (wake-up) 대기

이은 여러 스레드 간의 협력 메커니즘 . 우리는 종종 스레드에 대해 이야기 같은 경쟁에 자물쇠로 스레드 (인종), 사이 생각할 경쟁하지만,이 모든 이야기하지, 스레드 간의 협력 메커니즘이 될 것입니다 . 회사에서처럼 당신과 당신의 동료, 당신은 경쟁의 촉진에 존재할 수 있지만, 더 자주 더 많은 작업을 함께 특정 작업을 수행 할 수있다.

/ 알릴 (1) 대기 스레드 간의 협력기구이다.
즉, 스레드 소정의 동작 후에는 (대기 ())가 대기 상태로 진입하고, 지정된 코드의 종료 후, 다른 스레드는 웨이크 후에도 실행 대기 (알림 ()) ; 대기 다중 스레드있을 때 하면 필요한 경우, 사용의 notifyAll () 모든 대기 스레드를 깨워합니다 .

의 웨이크 업 방법 (2) 대기
모닝콜 장치가 대기하는 데 사용되는 스레드 간 통신의 문제를 해결하는 세 가지 방법을 사용하는 의미로서 다음이다 :

  1. 기다릴 : 스레드가 더 이상 더 이상 일정에 참여 활성화, 대기 세트 (세트)를 입력, 그래서 경쟁 잠금으로, CPU 자원을하지 낭비하지 말고, 다음 대기 상태를 스레드. 또한 "이며, 특정 작업을 수행 할 수있는 또 다른 스레드를 기다리고 에 규정 된 대기에서 스레드의 릴리스가 나올 때까지 기다리는이 개체에 (통지) 통보"의 스케줄링 큐 (준비 큐)를 다시 입력
  2. 통지 다음은 선택 해제의 스레드 (큐 스토리지) 통지 객체 대기 세트 , 예를 들어, 가능한 식당의 위치가 고객이 가장 오래된 제 장착 식사 기다린다.
  3. 가는 notifyAll : 알림 객체의 대기 세트에있는 모든 스레드가 해제됩니다.

참고 :
대기 스레드를 알려에도 경우에만 원래 동기화 블록에 중단 된 위치 때문에, 스레드는 즉시 실행을 재개 통보되지 수 없습니다, 하지만 그녀는 (잠금을 획득하기 위해 다시 시도 할 필요가 있으므로 순간에 더 이상, 잠금을 보유하고 원래 통화 대기 방법 후 복구 할 수있는 장소에 구현의 성공 후 다른 스레드에서 얼굴 경쟁), 가능성이 높습니다.

다음과 같이 요약 :
(1) 그들은 잠금을 얻을 수 있다면, 스레드는 대기 상태 RUNNABLE 상태가된다
(2) 그렇지 않으면, 대기에서 밖으로 설정하고 대기 상태에서 엔트리 세트로, 스레드와 국가 차단된다

개체의 잠금 대기에 전화 통지 방법은 세부 사항에 관심을 지불 할 필요가

  1. 기다려 방법 방법은 동일한 로크 대상에 의해 호출되어야 통지. 때문에 : 잠금 알릴 수있는 객체에 해당하는 온 같은 잠금 사용 일어나
    메소드 호출로 대기 한 후 스레드를.
  2. 알리고 대기 방법은 객체의 클래스에 속하는 방법이다. 때문에 : 락 객체가 어떤 객체가 될 수 있으며, 클래스에 속한 객체는 다음과 같다
    Object 클래스의 순서를.
  3. 방법 및 대기 방법은 통보해야 동기 또는 동기 블록 기능 . 때문에 :로해야 객체를 호출은 잠 이 두 정사각형
    방법.

3, 생산자와 소비자 문제

웨이크 업 메커니즘 기다립니다 실제로 고전 "생산자 - 소비자"문제입니다.

어떻게 자원의 웨이크 업 (wake-up)을 효과적으로 사용 대기 :
빵의 바 오즈 푸 스레드 생산, 만두 소비자 식품 제품 스레드를. 시간이 빵없는 경우, 식품 상품 바 오즈 푸 스레드 생산 만두 기다리는 스레드 (만두 상태는 거짓)
은 다음 바 오즈 푸 스레드 만두로되어있는 한, (즉, 만두 상태가 true), 및 통지 식품 제품 스레드 (리프트 식품 제품이 대기 상태) 대기 상태로.

다음으로, 제품 스레드가 경우의 추가 구현이 잠금에 따라 얻을 수 있습니다 먹는다. 당신은 잠금, 다음 작업 롤빵의 구현, 빵 먹고 (만두 상태가 false) 얻을 수있는 제품을 먹는 경우 와 대기에 바 오즈 푸 스레드 (방출 대기 상태 바 오즈 푸), 식품 제품 스레드를 통지 . 바 오즈 푸 쓰레드 케이스의 상기 구현이 로크에 따라 얻을 수있다.
그림 삽입 설명 여기
코드 보여줍니다

/**
 * 包子类
 * @author Mango
 */
public class BaoZi {

    String pi;
    String xian;
    boolean flag = false;

}
/**
 * 包子铺
 */
public class BaoZiShop extends Thread{

    private BaoZi baoZi;

    public BaoZiShop(String name, BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        int count = 0;
        //造包子
        while(true) {
            synchronized (baoZi) {
                if (baoZi.flag) {
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //没有包子 造包子
                System.out.println("包子铺开始做包子了");
                if(count %2 ==0) {
                    baoZi.pi = "冰皮";
                    baoZi.xian = "五仁";
                }else {
                    baoZi.pi = "薄皮";
                    baoZi.xian = "牛肉";
                }
                count++;

                baoZi.flag = true;
                System.out.println(baoZi.pi + baoZi.xian + "造好了");
                baoZi.notify();
            }
        }
    }
}
/**
 * 顾客
 * @author Mango
 */
public class Customer extends Thread{

    private BaoZi baoZi;

    public Customer(String name,BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (baoZi) {
                if(!baoZi.flag) {
                    //没包子
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("顾客正在吃" + baoZi.pi + baoZi.xian + "包子");
                baoZi.flag = false;
                baoZi.notify();
            }
        }
    }

}

二、线程池

1、线程池思想概述

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低
系统的效率,因为频繁创建线程和销毁线程需要时间

那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?在Java中可以通过与连接池类似的线程池来达到这样的效果。

2、线程池概念

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

线程池原理如图:
그림 삽입 설명 여기
合理利用线程池能够带来三个好处:

  1. 降低资源消耗。减少了线程创建销毁的过程(j节约资源),每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内
    存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

3、线程池的使用

최상위 인터페이스 내부에 자바 스레드 풀 java.util.concurrent.Executor를하지만, 엄밀한 의미 executor 스레드의 아닌
풀은 있지만 실행 도구의 하나 개의 스레드. 실제 스레드 풀 인터페이스는 java.util.concurrent.ExecutorService이다.
그림 삽입 설명 여기
구성하려면 스레드 풀은 특히 매우 분명하지 않다 스레드 풀의 원칙 아래를 들어, 더 복잡, 스레드 풀의 가능성이 구성 따라서 java.util.concurrent.Executors 내부 스레드 팩토리 클래스를 제공, 우수한 아니다 일부 정적 공장은 몇 가지 일반적인 스레드 풀을 생성합니다. 공식 권장 집행 인은 스레드 풀 개체를 만들 엔지니어링.

집행 클래스는 다음과 같이 스레드 풀을 만들었습니다 :
(1)public static ExecutorService newFixedThreadPool(int nThreads): 스레드 풀 오브젝트를 돌려줍니다. (만든이 묶여있다
최대 번호를 지정할 수 있습니다 풀의 스레드 수 인, 수영장을 멀리)

스레드 풀 ExecutorService를 객체를 얻으려면 다음과 같이 사용하는 방법, 여기 스레드 풀 개체를 사용하는 방법을 정의
(1)public Future<?> submit(Runnable task): 하나 개의 스레드 풀 스레드 개체를 얻을 , 그리고 미래의 인터페이스를 수행 스레드를 기록하는 데 사용을 작업이 완료된 후 결과를 생산했다. 만들기 및 스레드 풀을 사용하여.

사용 단계 스레드 풀 스레드 개체 :

  1. 스레드 풀 개체를 만듭니다.
  2. 실행 가능한 인터페이스는 하위 개체를 만들 수 있습니다. (작업)
  3. 의 Runnable 인터페이스 서브 클래스 객체를 제출합니다. (테이크 작업)
  4. 스레드 풀을 (일반적으로하지)를 닫습니다.

실행 가능한 구현 클래스 코드 :

/**
 * 创建一个Runnable接口的实现类
 * @author Mango
 */
public class DomeRunnable implements Runnable {

    /**
     * 重写接口的run方法,设置线程任务
     */
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i );
        }
    }
}
/**
 * 测试线程池
 */
public class Demo2 {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
		//创建Runnable实例对象
        DomeRunnable runnable = new DomeRunnable();

		//从线程池中获取线程对象,然后调用runnable对象中的run()
        service.submit(runnable);
        service.submit(runnable);
    }
}
게시 47 개 원래 기사 · 원의 찬양 (18) · 전망 4860

추천

출처blog.csdn.net/qq_43605085/article/details/102301958