목차
一、为何提供Lock接口?
二、死锁问题
三、synchronized的局限性
四、解决问题
1. Lock 인터페이스를 제공하는 이유는 무엇인가요?
2. 교착상태 문제
3. 동기화의 제한
4. 문제 해결
Java java지도 시간 Java가 단순히 동기화된 키워드를 사용하는 대신 잠금을 제공해야 하는 이유는 무엇입니까?

Java가 단순히 동기화된 키워드를 사용하는 대신 잠금을 제공해야 하는 이유는 무엇입니까?

Apr 20, 2023 pm 05:01 PM
java synchronized lock

요약: 동기화 키워드는 하나의 스레드만 동기화된 코드 블록에 액세스할 수 있도록 Java에서 제공됩니다. syncised 키워드가 제공되는데 Java SDK 패키지에 Lock 인터페이스도 제공되는 이유는 무엇입니까? 이것이 불필요한 바퀴의 재발명인가? 오늘 우리는 이 문제에 대해 함께 논의해 보겠습니다.

synchronized 키워드는 하나의 스레드만 동기화된 코드 블록에 액세스할 수 있도록 Java에서 제공됩니다. synchronized 키워드가 제공되었는데 Java SDK 패키지에 Lock 인터페이스도 제공되는 이유는 무엇입니까? 이것이 불필요한 바퀴의 재발명인가요? 오늘 우리는 이 문제에 대해 함께 논의해 보겠습니다. synchronized关键字来保证只有一个线程能够访问同步代码块。既然已经提供了synchronized关键字,那为何在Java的SDK包中,还会提供Lock接口呢?这是不是重复造轮子,多此一举呢?今天,我们就一起来探讨下这个问题。

问题?

既然JVM中提供了synchronized关键字来保证只有一个线程能够访问同步代码块,为何还要提供Lock接口呢?这是在重复造轮子吗?Java的设计者们为何要这样做呢?让我们一起带着疑问往下看。

一、为何提供Lock接口?

很多小伙伴可能会听说过,在Java 1.5版本中,synchronized的性能不如Lock,但在Java 1.6版本之后,synchronized做了很多优化,性能提升了不少。那既然synchronized关键字的性能已经提升了,那为何还要使用Lock呢?

如果我们向更深层次思考的话,就不难想到了:我们使用synchronized加锁是无法主动释放锁的,这就会涉及到死锁的问题。

二、死锁问题

如果要发生死锁,则必须存在以下四个必要条件,四者缺一不可。

Java가 단순히 동기화된 키워드를 사용하는 대신 잠금을 제공해야 하는 이유는 무엇입니까?

  • 互斥条件

在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待。

  • 不可剥夺条件

线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己来释放(只能是主动释放)。

  • 请求与保持条件

线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放。

  • 循环等待条件

在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。

三、synchronized的局限性

如果我们的程序使用synchronized关键字发生了死锁时,synchronized关键是是无法破坏“不可剥夺”这个死锁的条件的。这是因为synchronized申请资源的时候, 如果申请不到, 线程直接进入阻塞状态了, 而线程进入阻塞状态, 啥都干不了, 也释放不了线程已经占有的资源。

然而,在大部分场景下,我们都是希望“不可剥夺”这个条件能够被破坏。也就是说对于“不可剥夺”这个条件,占用部分资源的线程进一步申请其他资源时, 如果申请不到, 可以主动释放它占有的资源, 这样不可剥夺这个条件就破坏掉了。

如果我们自己重新设计锁来解决synchronized的问题,我们该如何设计呢?

四、解决问题

了解了synchronized的局限性之后,如果是让我们自己实现一把同步锁,我们该如何设计呢?也就是说,我们在设计锁的时候,要如何解决synchronized的局限性问题呢?这里,我觉得可以从三个方面来思考这个问题。

Java가 단순히 동기화된 키워드를 사용하는 대신 잠금을 제공해야 하는 이유는 무엇입니까?

(1)能够响应中断。 synchronized

🎜질문이 있으신가요? 🎜🎜🎜단 하나의 스레드만 동기화된 코드 블록에 액세스할 수 있도록 JVM에서 동기화 키워드가 제공되는데 왜 Lock 인터페이스를 제공해야 합니까? 이것이 바퀴를 재발명하는 것입니까? Java 디자이너는 왜 이런 일을 하는가? 질문과 함께 함께 살펴보겠습니다. 🎜

1. Lock 인터페이스를 제공하는 이유는 무엇인가요?

🎜많은 친구들이 Java 1.5 버전에서는 동기화 성능이 Lock만큼 좋지 않았지만 Java 1.6 버전 이후에는 synchronized가 많은 최적화를 거쳐 성능이 향상되었다는 이야기를 들었을 것입니다. 많이. 그렇다면 동기화 키워드의 성능이 향상되었는데 왜 여전히 Lock을 사용합니까? 🎜🎜더 깊게 생각해 보면 생각하기 어렵지 않습니다. synchronized를 사용하여 잠금을 설정하면 잠금을 적극적으로 해제할 수 없으므로 교착 상태 문제가 발생합니다. 🎜

2. 교착상태 문제

🎜 교착상태가 발생하려면 다음 네 가지 필수 조건이 있어야 하며, 이 네 가지 중 필수 조건은 없습니다. 🎜🎜Java에서 동기화를 제공한 후 Lock을 제공하는 이유는 무엇입니까 🎜
  • 🎜🎜상호 배제 조건🎜🎜
🎜🎜특정 리소스는 일정 시간 동안 하나의 스레드만 점유합니다. 이때 다른 스레드가 리소스를 요청하면 요청한 스레드는 대기만 할 수 있습니다. 🎜🎜
  • 🎜🎜양립할 수 없는 조건🎜🎜
🎜스레드에서 얻은 리소스는 사용되기 전에 다른 스레드에서 강제로 가져갈 수 없습니다. 즉, 리소스를 획득한 스레드에 의해서만 해제될 수 있습니다(활성적으로만 해제될 수 있음). 🎜
  • 🎜🎜요청 및 보류 조건🎜🎜
🎜스레드가 하나 이상의 리소스를 보유했지만 새 리소스 요청을 했습니다. 해당 리소스는 이미 다른 스레드에 의해 점유되어 있습니다. 이때 요청 스레드는 차단되지만 획득한 리소스는 유지됩니다. 🎜
  • 🎜🎜Loop 대기 조건🎜🎜
🎜 교착 상태가 발생하면 프로세스 대기 대기열 {P1, P2,&hellip이 있어야 합니다. ,Pn}, 여기서 P1은 P2가 점유한 자원을 기다리고, P2는 P3이 점유한 자원을 기다리고,..., Pn은 P1이 점유한 자원을 기다리며 프로세스 대기 루프를 형성합니다. 루프의 프로세스가 다른 프로세스에 의해 동시에 점유된다는 것은 전자 프로세스가 후자 프로세스가 소유한 자원을 점유한다는 것을 의미합니다. 🎜

3. 동기화의 제한

🎜우리 프로그램이 synchronized 키워드를 사용하고 교착 상태가 발생하는 경우 동기화의 핵심은 "양할 수 없는" 조건을 파괴할 수 없다는 것입니다. 왜냐하면 동기화를 자원에 적용할 때 응용이 불가능하면 스레드는 바로 차단 상태로 들어가고, 차단 상태에 들어가면 아무 것도 할 수 없고, 이미 스레드가 점유하고 있는 자원을 해제할 수도 없기 때문이다. 🎜🎜그러나 대부분의 시나리오에서는 "양도할 수 없는" 조건이 파기될 수 있기를 바랍니다. 즉, "비박탈" 조건의 경우, 일부 자원을 점유한 스레드가 다른 자원에 추가로 적용할 때, 적용할 수 없으면 자신이 점유하고 있는 자원을 적극적으로 해제할 수 있으므로 "비박탈" 조건이 됩니다. 박탈'이 파괴됩니다. 🎜🎜동기화 문제를 해결하기 위해 자물쇠를 스스로 다시 디자인한다면 어떻게 디자인해야 할까요? 🎜

4. 문제 해결

🎜동기화의 한계를 이해한 후, 동기화 잠금을 직접 구현할 수 있다면 어떻게 설계해야 할까요? 즉, 잠금을 설계할 때 동기화의 한계를 어떻게 해결합니까? 여기서 우리는 이 문제를 세 가지 측면에서 생각해 볼 수 있다고 생각합니다. 🎜🎜Java에서 동기화를 제공한 후 Lock을 제공하는 이유는 무엇입니까 🎜🎜(1) 인터럽트에 대응하는 능력. synchronized의 문제점은 잠금 A를 보유한 후 잠금 B를 획득하려는 시도가 실패하면 스레드가 차단 상태에 들어간다는 것입니다. 일단 교착 상태가 발생하면 차단된 스레드를 깨울 기회가 없습니다. 실. 그러나 차단된 스레드가 인터럽트 신호에 응답할 수 있다면, 즉 차단된 스레드에 인터럽트 신호를 보내면 이를 깨울 수 있으며, 그러면 한때 보유했던 잠금 A를 해제할 기회를 갖게 됩니다. 이는 양도할 수 없는 조건을 위반합니다. 🎜

(2) 지원 시간 초과. 스레드가 일정 시간 내에 잠금을 획득하지 못하고 차단 상태로 들어가는 대신 오류를 반환하는 경우 스레드는 한때 보유했던 잠금을 해제할 기회도 갖게 됩니다. 이는 또한 양도할 수 없는 조건을 약화시킬 것입니다.

(3) 비차단 방식으로 잠금을 획득합니다. 잠금 획득 시도가 실패하고 차단 상태로 진입하지 않고 직접 반환되는 경우 스레드는 한때 보유했던 잠금을 해제할 기회도 갖게 됩니다. 이는 또한 양도할 수 없는 조건을 약화시킬 것입니다.

는 Lock 인터페이스에서 제공하는 세 가지 메소드인

에 반영됩니다.

// 支持中断的API
void lockInterruptibly() throws InterruptedException;
// 支持超时的API
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 支持非阻塞获取锁的API
boolean tryLock();
로그인 후 복사
  • lockInterruptously()

는 인터럽트를 지원합니다.

  • tryLock() 메소드

tryLock() 메소드에는 잠금 획득을 시도하는 데 사용되는 반환 값이 있습니다. 획득에 성공하면 true를 반환합니다. , 다른 스레드에서 잠금을 획득한 경우) false를 반환합니다. 즉, 이 메서드는 무슨 일이 있어도 즉시 반환된다는 의미입니다. 자물쇠를 얻을 수 없을 때 거기에서 기다리지 않을 것입니다.

  • tryLock(장시간, TimeUnit 단위) 메서드

tryLock(장시간, TimeUnit 단위) 메서드는 tryLock() 메서드와 유사하지만 유일한 차이점은 이 메서드가 잠금을 획득하지 못한 경우 일정 시간 동안 대기합니다. 제한 시간 내에 잠금을 획득하지 못한 경우 false를 반환합니다. 잠금이 처음에 획득되었거나 대기 기간 동안 획득된 경우 true를 반환합니다. tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

也就是说,对于死锁问题,Lock能够破坏不可剥夺的条件,例如,我们下面的程序代码就破坏了死锁的不可剥夺的条件。

public class TansferAccount{
    private Lock thisLock = new ReentrantLock();
    private Lock targetLock = new ReentrantLock();
    //账户的余额
    private Integer balance;
    //转账操作
    public void transfer(TansferAccount target, Integer transferMoney){
        boolean isThisLock = thisLock.tryLock();
        if(isThisLock){
            try{
                boolean isTargetLock = targetLock.tryLock();
                if(isTargetLock){
                    try{
                         if(this.balance >= transferMoney){
                            this.balance -= transferMoney;
                            target.balance += transferMoney;
                        }   
                    }finally{
                        targetLock.unlock
                    }
                }
            }finally{
                thisLock.unlock();
            }
        }
    }
}
로그인 후 복사

例外,Lock下面有一个ReentrantLock,而ReentrantLock支持公平锁和非公平锁。

在使用ReentrantLock的时候, ReentrantLock中有两个构造函数, 一个是无参构造函数, 一个是传入fair参数的构造函数。 fair参数代表的是锁的公平策略, 如果传入true就表示需要构造一个公平锁, 反之则表示要构造一个非公平锁。如下代码片段所示。

//无参构造函数: 默认非公平锁
public ReentrantLock() {
	sync = new NonfairSync();
} 
//根据公平策略参数创建锁
public ReentrantLock(boolean fair){
	sync = fair ? new FairSync() : new NonfairSync();
}
로그인 후 복사

锁的实现在本质上都对应着一个入口等待队列, 如果一个线程没有获得锁, 就会进入等待队列, 当有线程释放锁的时候, 就需要从等待队列中唤醒一个等待的线程。 如果是公平锁, 唤醒的策略就是谁等待的时间长, 就唤醒谁, 很公平; 如果是非公平锁, 则不提供这个公平保证, 有可能等待时间短的线程反而先被唤醒。 而Lock是支持公平锁的,synchronized不支持公平锁。

最后,值得注意的是,在使用Lock加锁时,一定要在finally{}

즉, 교착 상태 문제의 경우 Lock은 양도할 수 없는 조건을 파괴할 수 있습니다. 예를 들어 아래 프로그램 코드는 교착 상태의 양도할 수 없는 조건을 파괴합니다.
try{
    lock.lock();
}finally{
    lock.unlock();
}
로그인 후 복사

예외입니다. 잠금 아래에 ReentrantLock이 있고 ReentrantLock은 공정한 잠금과 불공정한 잠금을 지원합니다. ReentrantLock을 사용할 때 ReentrantLock에는 두 개의 생성자가 있는데, 하나는 매개변수 없는 생성자이고 다른 하나는 공정한 매개변수를 전달하는 생성자입니다. fair 매개변수는 잠금의 공정성 전략을 나타냅니다. true가 전달되면 공정한 잠금이 생성되어야 함을 의미하고, 그렇지 않으면 불공정 잠금이 생성되어야 함을 의미합니다. 이는 다음 코드 조각에 나와 있습니다.

rrreee 잠금 구현은 기본적으로 항목 대기 대기열에 해당합니다. 스레드가 잠금을 획득하지 못한 경우 스레드가 잠금을 해제하면 대기 중인 스레드가 대기 대기열에서 깨어나야 합니다. 공정한 잠금인 경우 깨우기 전략은 오랫동안 기다려온 사람을 깨우는 것입니다. 이는 매우 공평하며, 불공정한 잠금인 경우에는 이러한 공정성이 보장되지 않으며 대기 시간이 짧은 스레드입니다. 먼저 깨어날 수도 있습니다. 잠금은 공정한 잠금을 지원하지만 동기화는 공정한 잠금을 지원하지 않습니다. 🎜🎜마지막으로 Lock을 사용하여 잠글 때는 예를 들어 다음 코드 조각에 표시된 것처럼 finally{} 코드 블록에서 잠금을 해제해야 한다는 점에 유의할 가치가 있습니다. 🎜rrreee🎜🎜🎜참고: 🎜동기화 및 잠금에 대한 자세한 지침은 친구들이 직접 확인할 수 있습니다. 🎜🎜

위 내용은 Java가 단순히 동기화된 키워드를 사용하는 대신 잠금을 제공해야 하는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 제곱근 자바의 제곱근 Aug 30, 2024 pm 04:26 PM

자바의 제곱근 안내 여기서는 예제와 코드 구현을 통해 Java에서 Square Root가 어떻게 작동하는지 설명합니다.

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

자바의 암스트롱 번호 자바의 암스트롱 번호 Aug 30, 2024 pm 04:26 PM

자바의 암스트롱 번호 안내 여기에서는 일부 코드와 함께 Java의 Armstrong 번호에 대한 소개를 논의합니다.

Java의 난수 생성기 Java의 난수 생성기 Aug 30, 2024 pm 04:27 PM

Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

See all articles