텍스트
동시 환경에서 프로그래밍 할 때는 공유 리소스에 대한 상호 배타적 인 액세스를 보장하기 위해 여러 스레드 간의 작업을 동기화하기 위해 잠금 메커니즘이 필요합니다. 잠금은 성능 손상을 유발할 수 있으며, 이는 잘 알려진 것 같습니다. 그러나 잠금 자체는 성능이 많은 소비를 가져 오지 않으며 성능은 주로 스레드에서 자물쇠를 획득하는 과정입니다. 잠금 장치를 위해 경쟁하는 스레드가 하나만 있고 현재 멀티 스레드 경쟁이없는 경우 JVM은 최적화되며 잠금으로 인한 성능 소비는 기본적으로 무시할 수 있습니다. 따라서 잠금 작동을 표준화하고, 잠금의 사용 방법을 최적화하고, 불필요한 스레드 경쟁을 피하면 프로그램 성능을 향상시킬뿐만 아니라 불규칙한 잠금으로 인한 스레드 교착 상태의 가능성을 피하고 프로그램 견고성을 향상시킬 수 있습니다. 다음은 몇 가지 잠금 최적화 아이디어를 설명합니다.
1. 메소드를 잠그지 마십시오
잠금이 일반 멤버 함수에 추가되면 스레드는 메소드가있는 객체의 객체 잠금을 얻습니다. 이때 전체 객체가 잠겨 있습니다. 이것은 또한이 객체가 제공하는 여러 동기화 방법이 다른 서비스를 위해서라면 전체 객체가 잠겨 있으므로 한 비즈니스가 처리되면 다른 관련없는 비즈니스 스레드도 기다려야 함을 의미합니다. 다음 예는 이것을 보여줍니다.
LockMethod 클래스에는 두 가지 비즈니스 프로세스에서 호출되는 두 가지 동기화 방법이 포함되어 있습니다.
public class lockmethod {public synchronized void busia () {for (int i = 0; i <10000; i ++) {system.out.println (thread.currentthread (). getName ()+"비즈니스 a :"+i); }} public synchronized void busib () {for (int i = 0; i <10000; i ++) {system.out.println (thread.currentthread (). getName ()+"비즈니스 B :"+i); }}}Bussa는 비즈니스를 처리하는 데 사용되는 스레드 클래스이며 LockMethod의 Busia () 메소드를 호출합니다.
공개 클래스 Bussb 확장 스레드 {lockmethod lockmethod; void deal (lockmethod lockmethod) {this.lockmethod = lockmethod; } @override public void run () {super.run (); lockmethod.busib (); }}TestLockMethod 클래스는 비즈니스 처리를 위해 스레드 Bussa 및 BusSB를 사용합니다.
public class testlockmethod는 스레드 {public static void main (String [] args) {lockmethod lockmethod = new LockMethod (); Bussa Bussa = New Bussa (); BUSSB BUSSB = NEW BUSSB (); Bussa.deal (Lockmethod); bussb.deal (lockmethod); bussa.start (); bussb.start (); }}프로그램을 실행할 때 Thread Bussa를 실행하는 동안 BusSB는 LockMethod 객체 잠금이 스레드 Bussa에 의해 얻어지기 때문에 Bussib () 기능을 입력 할 수 없음을 알 수 있습니다.
2. 동기 코드 블록을 줄이고 데이터 만 잠그십시오.
때때로 프로그래밍 편의를 위해 일부 사람들은 큰 코드를 동기화했습니다. 이 코드 블록의 일부 작업이 공유 리소스와 관련이없는 경우, 오랫동안 잠금 장치를 유지하지 않도록 동기 블록 외부에 배치되어 다른 스레드가 대기 상태에 남아 있어야합니다. 특히 일부 사이클 작업 및 동기 I/O 작업. 코드의 라인 범위에서 동기화 블록을 줄이는 것뿐만 아니라 실행 로직에서도 동기화 블록을 줄여야합니다. 예를 들어, 동기화 블록에 유입되는 불필요한 논리를 최소화하기 위해 동기화 후 조건부 판단을 수행하지 않고 조건부를 충족하는 경우 조건부 판단을 추가하고 동기화하십시오.
3. 자물쇠에 자물쇠를 포함시키지 마십시오
이 상황은 종종 발생합니다. 스레드가 A 잠금을 얻은 후 동기화 메소드 블록에서 다른 객체의 동기화 메소드를 호출하고 두 번째 잠금을 얻습니다. 이로 인해 통화 스택에 여러 개의 잠금 요청이 발생할 수 있습니다. 멀티 스레딩의 경우 예외를 분석하기가 매우 복잡하고 어려워 교착 상태가 발생할 수 있습니다. 다음 코드는 다음을 보여줍니다.
동기화 된 (a) {synchronized (b) {}}또는 동기화 방법이 동기화 블록에서 호출됩니다.
동기화 된 (a) {b b = objarraylist.get (0); B.method (); // 이것은 동기화 방법입니다}해결책은 점프하고 자물쇠를 추가하고 잠금 장치를 포함하지 않는 것입니다.
{b b = null; 동기화 된 (a) {b = objarraylist.get (0); } b.method ();} 4. 자물쇠를 민영화하고 내부적으로 잠금을 관리하십시오
잠금 장치를 개인 물체로 사용하는 것이 더 안전하며 외부에서 얻을 수 없습니다. 객체는 다른 스레드에 의해 직접 잠겨있을 수 있으며 스레드는 객체의 객체 잠금을 보유합니다.
클래스 a {public void method1 () {}} class b {public void method1 () {a = new a (); 동기화 된 (a) {// 직접 잠금 a.method1 (); }}}이러한 사용 방식에서 객체 A의 객체 잠금 장치는 외부에 의해 유지되므로 외부의 여러 장소에서 잠금 장치를 사용하도록하는 것이 더 위험하며 코드의 논리적 흐름을 읽는 데 문제가 발생합니다. 더 좋은 방법은 클래스 내에서 잠금을 스스로 관리하고 외부 동기 체계가 필요할 때 인터페이스를 통해 동기화 작업을 제공하는 것입니다.
클래스 A {private 객체 잠금 = new Object (); public void method1 () {synchronized (lock) {}}} class b {public void method1 () {a = new a (); a.method1 (); }} 5. 적절한 잠금 분해를 수행하십시오
다음 절차를 고려하십시오.
공개 클래스 Gameserver {public map <string, list <player>> tables = new Hashmap <string, list <player>> (); public void join (player player, table) {if (player.getAccountBalance ()> table.getLimit ()) {synchronized (tables) {list <layer> tablesplayers = tables.get (table.getId ()); if (tablePlayers.size () <9) {tablePlayers.add (플레이어); }}}}} public void Leave (플레이어 플레이어, 테이블 테이블) {/*avit*/} public void createTable () {/*omit*/} public void destroytable (테이블 테이블) {/*omit*/}}이 예에서 결합 메소드는 하나의 동기화 잠금을 사용하여 테이블에서 목록 <layer> 객체를 얻은 다음 플레이어 수가 9 미만인지 여부를 결정합니다. 그렇다면 플레이어 한 명을 추가하십시오. 테이블에 수천 개의 목록이 있으면 테이블 잠금 장치 경쟁이 매우 치열해질 것입니다. 여기서 잠금 장치 분해를 고려할 수 있습니다. 데이터를 신속하게 가져 오면 목록 <layer> 객체를 잠그십시오. 다른 스레드가 테이블 객체 잠금을 얻기 위해 빠르게 경쟁 할 수 있습니다.
공개 클래스 Gameserver {
공개지도 <문자열,
List <layer>> tables = new Hashmap <String,
목록 <플레이어 >> ();
공개 void 조인 (플레이어 플레이어, 테이블 테이블) {
if (player.getAccountBalance ()> table.getLimit ()) {
List <Payer> 테이블 플레이어 = NULL;
동기화 (테이블) {
TablePlayers = tables.get (table.getId ());
}
동기화 (테이블 플레이어) {
if (tablePlayers.size () <9) {
테일리 플레이어 .add (플레이어);
}
}
}
}
공개 무효 휴가 (플레이어 플레이어, 테이블 테이블) {
/*생략*/
}
public void createTable () {
/*생략*/
}
공개 void destroytable (테이블 테이블) {
/*생략*/
}
}