자바 스 레 드 간 공유 실현 방법 상세 설명
synchronize 는 다 중 스 레 드 키 워드 는 동기 화 자물쇠 로 다음 과 같은 몇 가지 대상 을 수식 할 수 있 습 니 다.
코드 블록:수 정 된 코드 블록 은 동기 코드 블록 이 라 고 불 리 며,역할 의 범 위 는{}안의 코드 이 며,역할 의 대상 은 이 코드 블록 을 호출 하 는 대상 입 니 다.
방법:수 정 된 방법 을 동기 화 방법 이 라 고 하 는데 작용 의 범 위 는 전체 방법 이 고 작용 의 대상 은 이 방법 을 호출 하 는 대상 이다.
클래스:역할 의 범 위 는 synchronize 뒤의 괄호 안의 부분 이 고 역할 의 대상 은 현재 클래스 입 니 다.
1.대상 잠 금
다음은 밤 하나 로 들 어 갑 니 다.
public class TestSynchronize {
//
private synchronized void syn(){
// sleep
SleepTools.second(2);
System.out.println("syn is going..."+this.toString());
SleepTools.second(2);
System.out.println("syn ended..."+this.toString());
}
// 1
private static class thread implements Runnable{
private TestSynchronize testSynchronize;
public thread(TestSynchronize testSynchronize){
this.testSynchronize = testSynchronize;
}
@Override
public void run() {
System.out.println("thread is running...");
testSynchronize.syn();
}
}
// 2
private static class thread2 implements Runnable{
private TestSynchronize testSynchronize;
public thread2(TestSynchronize testSynchronize){
this.testSynchronize = testSynchronize;
}
@Override
public void run() {
System.out.println("thread2 is running...");
testSynchronize.syn();
}
}
public static void main(String[] args) {
TestSynchronize testSynchronize = new TestSynchronize();
thread thread = new thread(testSynchronize);
TestSynchronize testSynchronize2 = new TestSynchronize();
thread2 thread2 = new thread2(testSynchronize);
//thread2 thread2 = new thread2(testSynchronize2);
new Thread(thread).start();
new Thread(thread2).start();
}
}
/**
testSynchronize ( ) :
thread is running...
thread2 is running...
syn is going...com.zl.synchronize.TestSynchronize@6b52350c
syn ended...com.zl.synchronize.TestSynchronize@6b52350c
syn is going...com.zl.synchronize.TestSynchronize@6b52350c
syn ended...com.zl.synchronize.TestSynchronize@6b52350c
*/
/**
testSynchronize, testSynchronize2 :
thread is running...
thread2 is running...
syn is going...com.zl.synchronize.TestSynchronize@28835f5f
syn is going...com.zl.synchronize.TestSynchronize@47c48106
syn ended...com.zl.synchronize.TestSynchronize@28835f5f
syn ended...com.zl.synchronize.TestSynchronize@47c48106
*/
결론:여러 스 레 드 가 같은 대상 을 호출 하 는 동기 화 방법 이 막 히 고 서로 다른 대상 을 호출 하 는 동기 화 방법 이 막 히 지 않 습 니 다.2.유형 자물쇠
1)synchronized 수식 의 정적 방법
public static synchronized void obj3() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
2)synchronized(test.class),자물쇠 의 대상 은 test.class,즉 test 류 의 자물쇠 입 니 다.
public void obj1() {
synchronized (test.class) {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
그러면 문제 가 생 겼 습 니 다.한 가지 유형 에서 두 가지 방법 이 있 는데 각각 synchronized 로 수식 하 는 정적 방법(클래스 잠 금)과 비 정적 방법(대상 잠 금)이 있 습 니 다.다 중 스 레 드 가 두 가지 방법 에 접근 할 때 스 레 드 가 막 히 지 않 습 니까?정 답 은 자물쇠 와 대상 자물쇠 가 동시에 존재 할 때 다 중 스 레 드 가 접근 할 때 막 히 지 않 는 다 는 것 이다.왜냐하면 그들 은 자물쇠 가 아니 기 때문이다.
2.휘발 성
volatile 은 유형의 수정자 입 니 다.volatile 의 역할 은 명령 키워드 로 서 이 명령 이 컴 파일 러 의 최적화 로 인해 생략 되 지 않도록 하 는 것 이다.
volatile 의 특성
4.567917.서로 다른 스 레 드 가 이 변 수 를 조작 할 때의 가시 성 을 확보 했다.즉,한 스 레 드 가 특정한 변수의 값 을 수정 했다.이 새 값 은 다른 스 레 드 에 있어 서 즉시 볼 수 있다.(가시 성 실현)
4.567917.ThreadLocal 은 글자 의 의미 에서 이해 할 수 있 고 스 레 드 로 컬 변수 이 며 스 레 드 로 컬 변수 라 고도 할 수 있 습 니 다.때때로 한 대상 의 변수 가 여러 스 레 드 에 접근 할 때 스 레 드 안전 문제 가 발생 할 수 있 습 니 다.물론 synchronized 키 워드 를 사용 하여 이 변 수 를 잠 글 수 있 습 니 다.동기 화 처 리 를 통 해 한 스 레 드 만 이 변 수 를 사용 할 수 있 도록 제한 할 수 있 습 니 다.그러나 이렇게 하면 프로그램의 실행 효율 에 영향 을 줄 수 있 습 니 다.이때 ThreadLocal 은 사용 할 수 있 습 니 다.
public class ThreadLocalDemo {
private static ThreadLocal<Integer> number = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
private static class thread extends Thread{
@Override
public void run() {
Integer number = ThreadLocalDemo.number.get();
for (int i = 0; i < this.getId(); i++) {
number++;
}
System.out.println(this.getName()+"---"+this.getId()+"===="+number);
}
}
private static class thread2 extends Thread{
@Override
public void run() {
Integer number = ThreadLocalDemo.number.get();
for (int i = 0; i < this.getId(); i++) {
number++;
}
System.out.println(this.getName()+"---"+this.getId()+"===="+number);
}
}
public static void main(String[] args) {
new Thread(new thread()).start();
new Thread(new thread2()).start();
}
}
/**
Thread-0---12====13
Thread-2---14====15
*/
4.대기(Wait)와 알림(notify)다 중 스 레 드 간 의 협력 을 지탱 하기 위해 JDK 는 매우 중요 한 스 레 드 인 터 페 이 스 를 제공 합 니 다.wait()방법 과 알림 notify()방법 을 기다 리 는 것 입 니 다.이 두 가지 방법 은 Thread 클래스 가 아니 라 Object 클래스 에 출력 되 는 것 입 니 다.이것 은 모든 대상 이 이 두 가지 방법 을 호출 할 수 있다 는 것 을 의미한다.
대기/알림 의 고전 패 러 다 임
wait()방법 과 notify()방법 은 도대체 어떻게 일 합 니까?
하나의 스 레 드 가 object.wait()방법 을 호출 하면 object 대상 의 대기 열 에 들 어 갑 니 다.이 대기 열 에는 여러 스 레 드 가 있 을 수 있 습 니 다.시스템 이 여러 스 레 드 를 실행 하 는 동시에 대상 을 기다 리 기 때 문 입 니 다.
object.notify()방법 이 호출 될 때 이 대기 열 에서 무 작위 로 스 레 드 를 선택 하고 깨 웁 니 다.
notity()방법 을 제외 하고 Object 대상 은 notify All()과 유사 한 방법 이 있 습 니 다.notity 방법의 기능 과 대체적으로 일치 합 니 다.다른 것 은 이 대기 열 에서 기다 리 는 모든 스 레 드 를 무 작위 로 깨 우 는 것 이 아 닙 니 다.
object.wait()방법 은 함부로 호출 할 수 없습니다.대상 의 synchronzied 구문 에 포함 되 어야 합 니 다.wait()방법 이나 notity()방법 이 든 먼저 대상 의 모니터 를 얻어 야 합 니 다.
T1 과 T2 는 두 개의 스 레 드 를 표시 합 니 다.T1 은 wait()방법 을 정확하게 실행 하기 전에 object 대상 의 모니터 를 받 아야 합 니 다.wait()방법 이 실 행 된 후에 이 모니터 를 방출 합 니 다.
이렇게 하 는 목적 은 다른 object 대상 에서 기다 리 는 스 레 드 가 T1 의 휴면 으로 인해 모두 정상적으로 실행 되 지 않도록 하 는 것 이다.
스 레 드 T2 는 notity()방법 이 호출 되 기 전에 object 대상 의 모니터 를 가 져 와 야 합 니 다.이때 T1 은 이미 이 모니터 를 풀 었 다.그래서 T2 는 object 대상 의 모니터 를 순조롭게 얻 을 수 있 습 니 다.
이 어 T2 는 notify()방법 을 실행 하여 대기 스 레 드 를 깨 우려 고 시 도 했 습 니 다.여기 서 T1 을 깨 웠 다 고 가정 합 니 다.T1 이 깨 어 난 후에 해 야 할 첫 번 째 일 은 후속 코드 를 실행 하 는 것 이 아니 라 다시 시도 하 는 것 입 니 다.
object 대상 의 모니터 를 가 져 옵 니 다.이 모니터 는 T1 이 wait()방법 을 실행 하기 전에 가지 고 있 는 것 입 니 다.
잠시 얻 을 수 없다 면 T1 은 이 모니터 를 기 다 려 야 합 니 다.모니터 가 순조롭게 획득 되 어야 T1 은 진정한 의미 에서 계속 실 행 될 수 있다.
wait()와 notify()에 포 함 된 synchronized 문 구 를 실행 해 야 모니터 를 풀 수 있 습 니 다.
이해 하기 편리 하고 간단 한 사례:
public class testWaitAndNotify {
final static Object object = new Object();
public static class T1 extends Thread {
public void run() {
synchronized (object) {
try {
System.out.println(System.currentTimeMillis() + ":T1 start! ");
System.out.println(System.currentTimeMillis() + ":T1 wait for object");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + ":T1 end! ");
}
}
}
public static class T2 extends Thread {
public void run() {
synchronized (object) {
try {
System.out.println(System.currentTimeMillis() + ":T2 start! notify one thread");
object.notify();
sleep(5000);
System.out.println(System.currentTimeMillis() + ":T2 end! ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
}
}
/**
1571039516250:T1 start!
1571039516250:T1 wait for object
1571039516251:T2 start! notify one thread
1571039521251:T2 end!
1571039521251:T1 end!
*/
5.대기 시간 초과 모드전형 적 인 대기/알림 패 러 다 임 으로 인해 시간 을 초과 하여 기다 릴 수 없다.즉,소비자 가 자 물 쇠 를 얻 은 후에 조건 이 만족 하지 않 으 면 생산자 가 조건 을 바 꾸 기 전에 대기 상태 에 있 고 일부 실제 응용 에서 자원 을 낭비 하여 운행 효율 을 낮 출 수 있다.
의사 코드 는 다음 과 같다.
// mills, remaining, future
long future = System.currentTimeMillis() + mills;
long remaining = mills;
synchronized (lock) {
while (!condition && remaining > 0) {
wait(remaining);
remaining = future - System.currentTimeMillis();
}
//
}
6.join()join 은 스 레 드 에서'새치기'를 의미 합 니 다.어떤 스 레 드 가 join 을 대표 하 는 스 레 드 새치기 가 먼저 실 행 됩 니까?그러나 누구의 팀 을 삽입 하 는 지 에 대해 신경 을 썼 습 니 다.팀 에 끼어 서 게 를 먹 는 첫 번 째 사람 이 될 수 있 는 것 이 아니 라 현재 운행 스 레 드 앞 에 꽂 았 습 니 다.예 를 들 어 시스템 이 현재 운행 스 레 드 A,온라인 스 레 드 A 에서 스 레 드 B.join 방법 을 호출 했 습 니 다.그 다음 에 스 레 드 B 는 스 레 드 A 앞에서 먼저 실행 하고 스 레 드 B 가 모두 실 행 된 후에 야 스 레 드 A 를 계속 실행 할 것 이다.
말 이 많 지 않 으 면 코드 를 말 해라.
public class TestJoin {
private static class thread extends Thread{
private Thread t;
//
public thread(Thread t){
this.t = t;
}
@Override
public void run() {
try {
// join
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"--- !");
}
}
public static void main(String[] args) throws InterruptedException {
//
Thread pre = Thread.currentThread();
//
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new thread(pre),String.valueOf(i));
//
thread.start();
//
pre = thread;
}
System.out.println(System.currentTimeMillis());
// 2s
Thread.currentThread().sleep(2000);
System.out.println(System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+"--- ");
}
}
/**
1571061168064
1571061170065
main---
Thread-0--- !
Thread-1--- !
Thread-2--- !
Thread-3--- !
Thread-4--- !
*/
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.