여덟, 지식과 계약 요약 자바 멀티 스레딩 재단

I. 배경

이 말한다면 1. 이전 블로그는 우리가 지식 이전 기사 내 이전 블로그를 참조 할 수 있습니다 다음 우리를 위해 오늘 말 자바 계약을 멀티 스레딩의 기본과 실제 사례를 소개하지만, 잘못, 내가 메시지를 환영 수정하시기 바랍니다.

2.이 블로그를 작성하는 목적은 네트워크에서 자신의 지식을 개선하는 것입니다, 실제 프로젝트뿐만 아니라 일반적으로 축적에 따라, 지식을 더 잘 이해하는 데 도움이 모두 희망하는에 사용이, 미묘한가 형성된다 강력한 지식 네트워크, 및 ADO, 우리가 바에서 배우고 함께 작업 할 수 있습니다.

둘째, 동기 용기 (및 계약)

ArrayList에와 차이 1.Vector

1.1.ArrayList 목록 내부는 빠른 랜덤 액세스 할 수 있습니다 요소의 배열을 통해 달성되는 가장 일반적인 구현 클래스입니다. 단점은 어레이 크기가 저장 용량을 증가시키기위한 요구를 만족하지 않는 경우가 배열 각 요소 사이의 공간을 가질 수 즉, 데이터 저장 공간이 새로운 어레이에 복사되어 말할 필요하다. 또는 삽입의 ArrayList의 중간 위치에서 요소를 삭제하는 경우, 상기 어레이는 복사, 이동해야하고, 비용이 상대적으로 높다. 따라서, 삽입 및 삭제에 적합하지 않은 임의의 검색 및 탐색에 대해 적합하다.

1.2.Vector 및 ArrayList를 그냥 배열을대로 스레드 동기화를 지원하는 것을 제외하고는, 한 번에 하나의 스레드 만이 벡터를 작성할 수 있다는 달성 불일치가 발생 쓰는 동안 멀티 스레딩을 방지하지만, 높은 동기를 필요로하는 비용 따라서, 느린 접속에 비해 액세스 권한이 ArrayList를

참고 :  Vector의 스레드 - 안전, ArrayList의 스레드가 안전하지 않은

소스 벡터 클래스 (클래스의 소스 코드의 추가 () 메소드)

ArrayList의 소스 유형 (소스 추가 () 메소드)

2.HashTable 与의 HashMap

스레드 안전하지 2.1.HashMap 상기 해시 MAP 키와 값이 개체는, 상기 오브젝트가, 키 값에 매핑하고, 하위 인터페이스는 인터페이스 맵 인터페이스이며, 중복 된 키를 포함 할 수 있지만, 중복되는 값을 포함 할 수있다. HashMap의가 null 키와 널 (null) 값을 허용하고, 해시 테이블은 허용되지 않습니다.

2.2.HashTable 컬렉션 스레드 안전합니다.

경량 실현 (비 스레드 안전 구현)가 Map 인터페이스를 완료 한 2.3.HashMap 해시 테이블이되고, 가장 큰 차이점은 HashMap에 의한 것보다 더 높을 수 있습니다 비 스레드 안전, 효율성, 널 (null)와 키 (key)를 수 있다는 것입니다 해시 테이블.
HashMap의는 키 항목 또는 값, 그리고 허용 해시 테이블로 널 (null)을 할 수 있습니다.
HashMap의 해시 테이블 방법, 제거으로써 containsValue containsKey 교체가 포함되어 있습니다.

참고 : 해시 스레드 - 안전은 HashMap의는 스레드 - 안전하지 않은 .

3.ConcurrentHashMap

3.1 해시 안전 잠금하지만, 아래와 같이 단지 효율성의 영향 때문에,이 시간이 ConcurrentHashMap의, 원리를 발명, 스레드 잠금 작업을 할 수 있기 때문에 :

3.2.ConcurrentMap 중요한 실현 두 인터페이스 있습니다
ConcurrentHashMap의
(. 상기 p HMA ConcurrentHas 보상 동시 정렬 기능 지원) ConcurrentSkipListMap과는
ConcurrentHashMap의 내부 세그먼트 (세그먼트)이 다른 부분을 나타 내기 위해, 각 섹션들은 실제로
그들은 작은 해시 그것은 자신의 잠금 장치가 있습니다. 만큼 여러 수정은 다른 섹션에서 발생, 그들이 수있는
수행 보냅니다. 전체를 16 세그먼트 (세그먼트로 분할된다. 즉 업 동작을 수정하는 16 개 개의 동시 스레드이다.
이 같은 장면 무거운 쓰레드 로크 세분화함으로써 용액 로크 경합을 감소시킨다. 감소되는 코드의 대부분은 공유 변수
휘발성 키워드의 사용은 처음 성능의 내용이 매우 좋은 수정 획득의 목적을 선언합니다.

4.CountDownLatch

기능적으로 유사한 카운터를 사용하여 구현 될 수있는 패키지 밑에 위치 4.1.CountDownLatch java.util.concurrent의 클래스. 예를 들어, 다른 하나는, 당신은 (조인 () 메소드 유사) CountDownLatch를 달성하기 위해이 기능을 사용할 수 있습니다 수행하는 네 개의 작업 완료 후 수행하는 것이 대기, 작업 A를있다.

4.2. 코드

public class Test002 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("等待子线程执行完毕...");
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
                countDownLatch.countDown();// 每次减去1
                System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
                countDownLatch.countDown();
                System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
            }
        }).start();
        countDownLatch.await();// 调用当前方法主线程阻塞  countDown结果为0, 阻塞变为运行状态
        System.out.println("两个子线程执行完毕....");
        System.out.println("继续主线程执行..");
    }
}

4.3 결과

셋째, 동시 큐

1.는 JDK는 두 개의 동시 큐 구현을 제공 ConcurrentLinkedQueue를 대기열을 나타내는 고성능 인 인터페이스의 대표 BlockingQueue의 블록 큐, 큐로부터 상속 상관없이이다.

2.ConcurrentLinkedQueue가 : 매우 동시 큐에 적합한 장면, 잠금없는 높은 동시성 상태에서 높은 성능을 달성하기 위해, 그런데, BlockingQueue의에서 ConcurrentLinkedQueue를 일반적으로 좋은 성능은이 링크 노드에 근거한다. 안 바운드 형식의 thread 세이프 인 큐를 . 큐의 요소는 FIFO의 원칙을 따라야합니다. 제 머리되는 최신의 첨가의 끝 큐 null 요소를 허용하지 않는, 접합.

2.1.ConcurrentLinkedQueue 중요한 방법 : 부가과 쿠폰 ()는 (차이의 방법 아닐 ConcurrentLinkedQueue를)에 요소를 추가하는 방법으로서
, 조사 () 및 PEEK (주)의 요소를 제거하는 것을 제외하고, 제 1 엘리먼트 노드를 취한다 후자는하지 않습니다.

2.2 코드 (자기 일견 결과)

ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
	q.offer("小明");
	q.offer("小红");
	q.offer("小张");
	q.offer("小诺");
	q.offer("小华");
	//从头获取元素,删除该元素
	System.out.println(q.poll());
	//从头获取元素,不刪除该元素
	System.out.println(q.peek());
	//获取总长度
	System.out.println(q.size());

3.BlockingQueue : 블록 큐 (BlockingQueue의)는 두 개의 큐가 추가 작업을 지원한다. 이 두 가지 추가 작업은 다음과 같습니다 :

비어 될 큐의 스레드가 대기의 요소를 검색 할 때 3.1. 큐에 비어있다.
큐가 가득 차면, 스레드는 큐의 기억 소자를 사용할 대기합니다. 

일반적으로 생산자와 장면의 소비자에 사용되는 큐를 차단, 생산자는 큐 스레드 요소에 추가, 소비자는 큐의 스레드에서 요소를 가지고하는 것입니다. 큐 수납 용기 요소를 차단하면 생산하고, 소비자는 단지 상기 용기의 요소를 가지고.

큐에서 차단 3.2.BlockingQueue 차단 단어에서 본 경우에 따라서 발생할 수 블로킹 큐 액세스를 차단할 수있다. 경우 주요 다음이 차단 있습니다 :

대기열로 실시 할 때 1. 대기열이 가득 차면

2. 때 빈 큐 작업에 대한 큐 시간

스레드 시도 작업에 큐의 전체 큐를 가질 때 큐 작업을 수행하는 다른 스레드가없는 따라서이 차단 될 것이다 마찬가지로, 스레드는 큐 큐 작업을 비워 시도 큐 조작으로 다른 스레드가 없다면,이를 차단한다.

큐 블록킹 스레드 안전하다고 보여 상술 큐 특성을 차단하여 (Java5 버전부터 구입 가능) java.util.concurrent의 패키지에있는 3 자바, BlockingQueue의 인터페이스.

새로운 동시 패키지에서, 다중 스레드, 데이터 문제를 어떻게 효율적이고 안전한 "전송"에 BlockingQueue의 좋은 솔루션입니다. 이 효율적이고 스레드 안전 큐 클래스, 우리가 신속하게 고품질의 멀티 스레드 프로그램을 빌드하기위한 매우 편리. 본 논문은 BlockingQueue의 그들의 각각의 기능 및 일반적인 사용 시나리오를 포함한 가족의 모든 구성원에 대해 설명합니다.

이해 BlockingQueue의

이름에서 알 수 있듯이 다음과 같이이 제 큐 실질적 큐 데이터 구조의 역할, 블로킹 큐 :

도면에서 우리는 공유 된 큐를 통해 명확하게 볼 수 있도록, 데이터가 큐의 일단으로부터 입력이 타단으로부터 출력 될 수 있음;

대기열 물론 두 가지 :( 구현이 다른 경우도 큐의 많은 다른 유형을 연장 할 수있다,있다, DelayQueue를)가 그 중 하나입니다

  선입 선출 (FIFO)는 : 제 요소는 큐의 첫 번째 큐에 삽입 큐 기능처럼. 어느 정도, 이것은 또한 큐의 공정성을 반영한다.

  마지막으로, 첫 번째 출력 (LIFO) : 당신이 큐 큐, 최근의 사건의 큐 우선 순위의 첫 번째 요소를 삽입 한 후.

      환경 멀티 스레드, 데이터 공유가 쉽게 고전 '생산자'와 '소비자'모델로, 큐 통해 달성 될 수있다, 그것은 대기열을 통해 둘 사이의 데이터 공유를 용이하게 할 수있다. 우리가 생산자 스레드의 번호를 가지고 가정, 추가적인 소비자 스레드가 있습니다. 주 소비자에게 데이터를 준비 스레드, 큐 방식을 사용하는 생산자 스레드 필요가 데이터를 전달하는 경우, 쉽게 그들 사이의 문제를 공유하는 데이터를 해결할 수 있습니다. 그러나 이벤트의 일정 기간의 생산자와 소비자가, 상황이 데이터와 일치하지 않는 경우 처리 속도는 일이? 제조자 출력 데이터 비율이 소비 속도 및 어느 정도 밖에 누적 생산 데이터보다 큰 경우 이상적 후 제조자는 소비자가 기다리는하기 위해서는, (블로킹 제조자 스레드)을 기다릴 중지해야 축적 된 데이터를 처리하는 스레드와 반대로된다. 그러나, 동시 릴리스 패키지하기 전에, 다중 스레드 환경에서, 우리는뿐만 아니라 효율성과 스레드 안전에, 이러한 세부 사항을 제어하는 ​​모든 프로그래머를 소유하고 특히해야하고, 이것은 우리의 프로그램은 복잡성의 작은도없는 줄 것이다 . 다행히 이번에는 강력한 동시 패키지 밝혀졌다, 그러나 그는 또한 우리에게 강력한 BlockingQueue의를 제공합니다. (다중 스레드 지역에서 : 소위 차단, 어떤 경우에는 자동으로 조건이 충족되면, 일시 중단 된 스레드가 깨어됩니다 (즉, 차단) 스레드를 걸어).

4. 다음 그림을 보여줍니다이 BlockingQueue의 두 가지 일반적인 차단 시나리오 :

4.1.ArrayBlockingQueue : 한 큐 테두리 차단 내부 구현은 배열있다. 용량이 경계를 의미한다하는 것은 제한된다, 우리는 초기화시 용량의 크기를 지정할 수 있고, 지정된 크기의 용량은 불변되면. ArrayBlockingQueue 등 최신의 목적은 헤드에서 제거되고, FIFO에 저장된 데이터는 새로 삽입 된 개체 테일이다. 다음은 초기화 및 사용에 ArrayBlockingQueue의 예입니다 :

ArrayBlockingQueue<String> arrays = new ArrayBlockingQueue<String>(3);
	arrays.add("李四");
	 arrays.add("张军");
	arrays.add("张军");
	// 添加阻塞队列
	arrays.offer("张三", 1, TimeUnit.SECONDS);

초기화 할 때 우리가 크기를 지정하면 4.2.LinkedBlockingQueue 블로킹 큐 크기 구성은 경계선이며, 지정되지 않은 경우가 묶여있다, 선택 사항입니다. 그는 국경으로, 사실에 Integer.MAX_VALUE 용량의 기본 크기를 사용하는 것입니다 말했다. 내부 구현은 링크 된 목록입니다.

그리고 ArrayBlockingQueue를 같이하는 FIFO 방식으로도 LinkedBlockingQueue 등 저장 데이터는 새로 삽입 된 개체는 꼬리 최신 객체는 머리에서 제거된다. 다음은 예를 들어 초기화하고 LinkedBlockingQueue 등을 확인하는 것입니다 :

LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(3);
linkedBlockingQueue.add("张三");
linkedBlockingQueue.add("李四");
linkedBlockingQueue.add("李四");
System.out.println(linkedBlockingQueue.size());

4.3.PriorityBlockingQueue 큐 테두리, 자사의 데이터 정렬 및 java.util.PriorityQueue 동일하지 않습니다. 널 객체 인 PriorityBlockingQueue 허가 삽입합니다. 인 PriorityBlockingQueue java.lang.Comparable 인터페이스를 구현해야합니다 삽입 된 모든 개체, 큐 우선 순위는 우리가이 인터페이스가 정의 실현 종류의 규칙에 따라입니다. 또한, 우리는 인 PriorityBlockingQueue에서 반복자 반복자를 얻을 수 있지만이 보장하지 않는 우선 순위에 따라 함께 반복자.

4.4. 코드 (사용 시뮬레이션 생산자와 소비자의 BlockingQueue )

class ProducerThread extends Thread {
    private BlockingQueue queue;
    private volatile boolean flag = true;
    private static AtomicInteger count = new AtomicInteger();
    ProducerThread(BlockingQueue blockingQueue) {
        this.queue = blockingQueue;
    }
    @Override
    public void run() {
        System.out.println("生产者线程启动...");
        try {
            while (flag) {
                System.out.println("正在生产队列");
                String data = count.incrementAndGet() + "";
                // 添加队列
                boolean offer = queue.offer(data);
                if (offer) {
                    System.out.println("生产者添加队列" + data + "成功!");
                } else {
                    System.out.println("生产者添加队列" + data + "失败!");
                }
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            System.out.println("生产者线程停止...");
        }
    }
    public void stopThread() {
        this.flag = false;
    }
}
class ConsumerThread extends Thread {
    private BlockingQueue queue;
    private volatile boolean flag = true;

    ConsumerThread(BlockingQueue blockingQueue) {
        this.queue = blockingQueue;
    }
    @Override
    public void run() {
        System.out.println("消费者线程启动....");
        try {
            while (flag) {
                // 获取完毕,队列会删除掉
                String data = (String) queue.poll(2, TimeUnit.SECONDS);
                if (data != null) {
                    System.out.println("消费者获取 data:" + data + "成功...");
                } else {
                    System.out.println("消费者获取 data:" + data + "失敗..");
                    this.flag = false;
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            System.out.println("消费停止....");
        }
    }
}
public class Test006 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
        ProducerThread p1 = new ProducerThread(queue);
        // ProducerThread p2 = new ProducerThread(queue);
        ConsumerThread c1 = new ConsumerThread(queue);
        p1.start();
        // p2.start();
        c1.start();
        // 执行10s
        Thread.sleep(10 * 1000);
        p1.stopThread();
        // p2.stopThread();
    }
}

4.4 결과

生产者线程启动...
正在生产队列
消费者线程启动....
生产者添加队列1成功!
消费者获取 data:1成功...
正在生产队列
生产者添加队列2成功!
消费者获取 data:2成功...
正在生产队列
生产者添加队列3成功!
消费者获取 data:3成功...
正在生产队列
生产者添加队列4成功!
消费者获取 data:4成功...
正在生产队列
生产者添加队列5成功!
消费者获取 data:5成功...
正在生产队列
生产者添加队列6成功!
消费者获取 data:6成功...
正在生产队列
生产者添加队列7成功!
消费者获取 data:7成功...
正在生产队列
生产者添加队列8成功!
消费者获取 data:8成功...
正在生产队列
生产者添加队列9成功!
消费者获取 data:9成功...
正在生产队列
生产者添加队列10成功!
消费者获取 data:10成功...
生产者线程停止...
消费者获取 data:null失敗..
消费停止....

넷째, 말

항상 믿음을 유지! 

게시 된 122 개 원래 기사 · 원 찬양 64 ·은 50000 +를 볼

추천

출처blog.csdn.net/chenmingxu438521/article/details/103833647