자바 는 두 개의 스 레 드 로 숫자 와 자 모 를 교체 인쇄 한다.

얼마 전에 말 병사 선생님 의 강 의 를 듣 고 한 회사 의 면접,두 개의 스 레 드 에 대해 이 야 기 를 했 습 니 다.그 중에서 한 스 레 드 는 ABC 를 수출 하고 다른 스 레 드 는 123 을 수출 합 니 다.두 스 레 드 의 교차 수출 을 어떻게 통제 하 는 지 저 는 다 중 스 레 드 를 잘 파악 하지 못 했 기 때문에 이 문 제 를 듣 고 개인 적 으로 많은 것 을 얻 었 습 니 다.이것 은 학습 노트 입 니 다.이 문 제 는 여러 가지 해법 이 있 지만 일 부 는 순 현 기 에 속 하기 때문에 흔히 볼 수 있 는 세 가지 해법 만 기록한다.일단 첫 번 째.
1.파 크 와 unpark

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
import java.util.concurrent.locks.LockSupport;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Park_Unpark {
 
    static Thread t1 = null;
    static Thread t2 = null;
 
    public static void main(String[] args) {
 
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        t1 = new Thread(() -> integers.forEach(item -> {
            System.out.print(item);
            LockSupport.unpark(t2);
            LockSupport.park();
        }), "t1");
 
        t2 = new Thread(() -> strings.forEach(item -> {
            LockSupport.park();
            System.out.print(item);
            LockSupport.unpark(t1);
        }), "t2");
 
        t1.start();
        t2.start();
    }
 
}
이것 은 가장 간단 한 실현 방법 입 니 다.LockSupport.park()는 현재 스 레 드 를 막 고 LockSupport.unpark()는 스 레 드 를 깨 우 는 것 을 표시 합 니 다.그래서 그 는 어떤 스 레 드 를 깨 우 고 싶 은 지 이해 하기 쉽 고 간단 한 매개 변수 가 필요 합 니 다.
2. synchronized、notify、wait

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Notify_Wait {
 
    public static void main(String[] args) {
 
        final Object o = new Object();
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        new Thread(() -> {
            synchronized (o) {
                integers.forEach(item -> {
                    System.out.print(item);
                    o.notify();
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
 
                o.notify();
            }
        }, "t1").start();
 
        new Thread(() -> {
            synchronized (o) {
                strings.forEach(item -> {
                    System.out.print(item);
                    o.notify();
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                o.notify();
            }
        }, "t2").start();
    }
}
이것 은 비교적 전통 적 인 서법 이자 이해 하기 어 려 운 서법 이다.이런 서법 을 파악 한 후에 synchronized,notify,wait 에 대한 인식 도 새로운 높이 가 있 을 것 이다.다음은 이런 서법 을 간단하게 해석 해 보 자.
우 리 는 모두 synchronized 가 자물쇠 라 는 것 을 알 고 있 습 니 다.자물쇠 가 무엇 입 니까?바로 제3자 가 서로 배척 하 는 자원 이다.그래서 synchronized(o)는 우리 가 o 라 는 대상 에 자 물 쇠 를 추가 한 것 은 o 의 대상 머리 를 수정 하여 이 루어 진 것 이다.즉,두 개의 스 레 드 가 o 의 대상 머리 를 성공 적 으로 수정 한 사람 이 이 자 물 쇠 를 받 은 다음 에 안의 관련 논 리 를 집행 할 수 있 고 o 의 대상 머리 스 레 드 를 성공 적 으로 수정 하지 못 했다.대상 o 의 대기 열 에 들 어가 서 시스템 에 의 해 실행 되 기 를 기다 리 는 것 만 있 습 니 다.그 다음 에 o.notify()입 니 다.방금 synchronized(o)한 무더기 의 스 레 드 가 자 물 쇠 를 빼 앗 지 못 했 습 니 다.자 물 쇠 를 빼 앗 지 못 한 스 레 드 가 대상 o 의 대기 열 에 들 어 갔 기 때문에 o.notify()의 미 는 대상 o 의 대기 열 에서 무 작위 로 스 레 드 를 깨 우 고 실행 하 는 것 입 니 다.마지막 으로 o.wait()의 의미 입 니 다.그의 의미 도 간단 합 니 다.바로 현재 스 레 드 를 대상 o 의 대기 열 에 놓 고 CPU 를 양보 하 는 것 입 니 다.
이 설명 을 통 해 자주 발생 하 는 세 가지 문제 가 어떻게 된 일 인지 배 울 수 있 습 니 다.1.wait 가 CPU 자원 을 점용 하 는 지,대기 열 에 들 어 갔 기 때문에 점용 하지 않 습 니 다.2.notify,wait 는 스 레 드 를 깨 우 고 스 레 드 를 기다 리 게 하 는 것 입 니 다.왜 Thread 류 의 방법 이 아니 라 Object 의 방법 입 니까?notify,wait 는 synchronized 와 함께 사용 되 기 때문에 다 중 스 레 드 에 사용 되 지 않 습 니 다.synchronized 잠 금 대상 의 대기 열 을 제어 하고 synchronized 잠 금 대상 을 제어 합 니 다.분명 Object 일 것 입 니 다.그래서 notify,wait,예 를 들 어 Object 대상 의 방법 입 니 다.3.synchronized(o)괄호 안에 대상 인 스 턴 스,Class 대상,잠 금 코드 블록,정적 변수 등 차이 가 있 습 니 다.synchronized 가 수정 한 것 이 무엇 인지 알 면 이러한 차 이 는 한눈 에 알 수 있 고 더 이상 군말 하지 않 습 니 다.
마지막 으로 설명 하고 자 하 는 문 제 는 바깥 을 순환 하 는 o.notify()가 없어 서 는 안 된다 는 것 이다.어떤 친구 들 은 쓸 때 손 쉽게 잊 어 버 리 거나 왜 마지막 에 notify 를 해 야 하 는 지 모 르 겠 지만 곰 곰 이 생각해 보면 알 수 있다.마지막 에 실 행 된 것 이 알파벳 을 지 는 스 레 드 라 고 가정 하면 그 는 반드시 출력 숫자의 스 레 드 에 의 해 깨 어 났 을 것 이다.출력 숫자 를 실행 하 는 이 스 레 드 는 출력 자 모 를 실행 하 는 스 레 드 를 깨 운 후에 자신 이 대기 열 에 들 어 갑 니 다.그래서 순환 이 끝 난 후에 마지막 으로 출력 자 모 를 실행 하 는 스 레 드 가 출력 숫자 를 실행 하 는 스 레 드 를 깨 우지 않 으 면 출력 숫자 를 실행 하 는 스 레 드 는 wait 가 계속 막 혀 서 황무지 에서 바닷물 이 마 르 고 돌 이 썩 을 때 까지 기다 릴 것 입 니 다.
3. Condition

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Condition {
 
    public static void main(String[] args) {
 
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
 
        new Thread(() -> {
            lock.lock();
            try {
                integers.forEach(item -> {
                    System.out.print(item);
                    condition2.signal();
                    try {
                        condition1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
 
                condition2.signal();
            } finally {
                lock.unlock();
            }
        }, "t1").start();
 
        new Thread(() -> {
            lock.lock();
            try {
                strings.forEach(item -> {
                    System.out.print(item);
                    condition1.signal();
                    try {
                        condition2.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                condition1.signal();
            } finally {
                lock.unlock();
            }
        }, "t2").start();
 
    }
 
}
우리 가 위의 두 가지 문법 을 이해 한 후에 마지막 으로 이 문법 도 사실 비교적 쉽게 이해 할 수 있 으 니 내 가 쓸데없는 말 을 할 필요 가 없다.
만약 에 친구 들 이 이곳 을 보 게 된다 면 저 는 작은 문 제 를 제기 하 겠 습 니 다.어떻게 해결 해 야 할 지 생각해 볼 수 있 습 니 다.뒤의 두 가지 쓰기 방법 을 생각해 볼 수 있 습 니 다.우 리 는 출력 숫자의 스 레 드 를 실행 할 것 인지,아니면 출력 알파벳 의 스 레 드 를 먼저 실행 할 것 인 지 를 보장 합 니 다.즉,먼저 숫자 나 자 모 를 출력 하 는 것 입 니까?만약 안 된다 면 현재 업무 수요 요 구 는 알파벳 이나 숫자 를 먼저 출력 해 야 합 니 다.어떻게 해 야 합 니까?알림:CAS 자전)
이상 은 자바 가 두 개의 스 레 드 로 숫자 와 알파벳 을 교체 인쇄 하 는 상세 한 내용 입 니 다.자바 스 레 드 교체 인쇄 에 관 한 자 료 는 우리 의 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기