방법 1: 동기화 키워드 사용
Java의 모든 객체에는 내장 잠금이 있으므로 이 키워드로 메서드를 수정하면 내장 잠금이 전체 메서드를 보호합니다. 이 메서드를 호출하기 전에 내장 잠금을 얻어야 합니다. 그렇지 않으면 차단됩니다.
참고: 동기화된 키워드는 정적 메서드를 수정할 수도 있습니다. 이때 정적 메서드를 호출하면 전체 클래스가 잠깁니다.
참고: 동기화는 오버헤드가 높은 작업이므로 동기화된 콘텐츠를 최소화해야 합니다. 일반적으로 전체 메소드를 동기화할 필요는 없으며, 동기화된 코드 블록을 사용하여 키 코드를 동기화하면 됩니다.
동기화 키워드는 공유 데이터를 보호하기 위해 사용됩니다. "공유 데이터"에 주의하세요. 어떤 데이터가 공유 데이터인지 구분해야 합니다
관련 동영상 튜토리얼 추천: java video
예:
package com.gcc.interview.synchro; public class MybanRunnable implements Runnable{ private Bank bank; public MybanRunnable(Bank bank) { this.bank = bank; } @Override public void run() { for(int i=0;i<10;i++) { bank.save1(100); System.out.println("账户余额是---"+bank.getAccount()); } } }
package com.gcc.interview.synchro; class Bank{ private int account = 100; public int getAccount() { return account; } //同步方法 public synchronized void save(int money) { account+=money; } public void save1(int money) { //同步代码块 synchronized(this) { account+=money; } } public void userThread() { Bank bank = new Bank(); MybanRunnable my1 = new MybanRunnable(bank); System.out.println("线程1"); Thread th1 = new Thread(my1); th1.start(); System.out.println("线程2"); Thread th2 = new Thread(my1); th2.start(); } }
방법 2: 기다리고 알림
wait(): 사용 스레드는 대기 상태에 있으며 보유하고 있는 개체에 대한 잠금을 해제합니다.
sleep(): 실행 중인 스레드를 절전 상태로 전환합니다. InterruptedException을 포착하려면 이 메서드를 호출합니다.
notify(): 대기 상태에 있는 스레드를 깨웁니다. 이 메서드를 호출하면 대기 상태에 있는 스레드를 정확히 깨울 수 없습니다. 대신 JVM이 어떤 스레드를 깨울지 결정하며 이를 기반으로 하지 않습니다. 우선순위에 .
Allnotity(): 대기 상태에 있는 모든 스레드를 깨우십시오. 깨어난 모든 스레드에 객체 잠금을 부여하는 것이 아니라 경쟁하게 하십시오.
방법 3: 특수 도메인 변수 휘발성을 사용하여 스레드 동기화 달성
a. 휘발성 키워드는 도메인 변수에 액세스하기 위한 잠금 없는 메커니즘을 제공합니다
b. 휘발성을 사용하여 도메인을 수정하는 것은 가상 머신에 알리는 것과 같습니다. 도메인이 가능하다는 사실은 다른 스레드에 의해 업데이트됩니다
c. 따라서 필드가 사용될 때마다 레지스터의 값을 사용하는 대신 다시 계산해야 합니다.
d.휘발성은 원자적 연산을 제공하지 않으며 그럴 수도 없습니다. 최종 유형 변수를 수정하는 데 사용됩니다.
예:
위의 예에서는 스레드 동기화를 달성하기 위해 계정 앞에 휘발성 수정을 추가하기만 하면 됩니다.
//只给出要修改的代码,其余代码与上同 class Bank { //需要同步的变量加上volatile private volatile int account = 100; public int getAccount() { return account; } //这里不再需要synchronized public void save(int money) { account += money; } }
참고: 멀티스레딩의 비동기화 문제는 주로 도메인을 읽고 쓸 때 발생합니다. 도메인 자체가 이 문제를 방지한다면 도메인 운영 방법을 수정할 필요가 없습니다. 최종 필드, 잠금 보호 필드 및 휘발성 필드를 사용하면 비동기화 문제를 방지할 수 있습니다.
방법 4: 재진입 잠금을 사용하여 스레드 동기화 달성
동기화를 지원하기 위해 새로운 java.util.concurrent 패키지가 JavaSE5.0에 추가되었습니다.
ReentrantLock 클래스는 Lock 인터페이스를 구현하는 재진입 상호 배타적 잠금입니다. 이는 동기화된 메서드 및 블록을 사용하는 것과 동일한 기본 동작 및 의미를 가지며 해당 기능을 확장합니다.
ReenreantLock 클래스에서 일반적으로 사용되는 메서드는 다음과 같습니다.
참고: ReentrantLock()에도 공정한 잠금을 생성할 수 있는 생성 메서드가 있지만 프로그램 운영 효율성을 크게 떨어뜨릴 수 있으므로 권장하지 않습니다.
private int account = 100; private ReentrantLock lock = new ReentrantLock(); public int getAccount() { return account; } //同步方法 public void save(int money) { lock.lock(); try { account+=money; } finally { lock.unlock(); } }
를 사용하세요. 잠금에 대한 객체 선택 및 동기화 키워드:
a 사용자가 모든 잠금 관련 코드를 처리하는 데 도움이 되도록 둘 다 사용하지 않고 java.util.concurrent 패키지에서 제공하는 메커니즘을 사용하는 것이 가장 좋습니다.
b. 동기화된 키워드가 사용자의 요구를 충족할 수 있다면 코드를 단순화할 수 있으므로 동기화를 사용하세요.
c. 더 고급 기능이 필요한 경우 이때 잠금을 해제하도록 주의하세요. 시간이 지나면 교착 상태가 나타나며 일반적으로 최종 코드에서 잠금이 해제됩니다.
방법 5: 로컬 변수를 사용하여 스레드 동기화 달성
ThreadLocal을 사용하여 변수를 관리하는 경우 변수를 사용하는 각 스레드는 복사본을 얻습니다. 변수의 사본은 상호 배타적이므로 각 스레드는 다른 스레드에 영향을 주지 않고 마음대로 변수의 자체 사본을 수정할 수 있습니다.
ThreadLocal 클래스의 일반적인 메서드
//只改Bank类,其余代码与上同 public class Bank{ //使用ThreadLocal类管理共享变量account private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){ @Override protected Integer initialValue(){ return 100; } }; public void save(int money){ account.set(account.get()+money); } public int getAccount(){ return account.get(); } }
참고: ThreadLocal 및 동기화 메커니즘
a. ThreadLocal 및 동기화 메커니즘은 모두 여러 스레드에서 동일한 변수에 대한 액세스 충돌 문제를 해결합니다.
b. 전자는 "공간을 시간으로 교환"하는 방식을 채택하고, 후자는 "시간을 공간으로 교환"하는 방식을 채택합니다.
추천 관련 기사 및 튜토리얼: Java 기초 없이 시작하기
위 내용은 Java에서 스레드 동기화를 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!