>  기사  >  Java  >  Java의 잠금이란 무엇입니까? Java의 잠금에 대한 자세한 소개

Java의 잠금이란 무엇입니까? Java의 잠금에 대한 자세한 소개

不言
不言원래의
2018-09-27 17:16:3510333검색

이 기사의 내용은 Java에서 잠금이 무엇인지에 관한 것입니다. Java의 잠금에 대한 자세한 소개는 특정 참고 가치가 있습니다. 도움이 필요한 친구가 참고할 수 있기를 바랍니다.

1. 소개

잠금은 java.util.concurrent 패키지 아래의 동기화 키워드 및 관련 클래스를 통해 JAVA에서 구현됩니다.

잠금 구현을 위해 Java에서 제공하는 관련 API:

Java의 잠금이란 무엇입니까? Java의 잠금에 대한 자세한 소개

Lock은 동기화된 동기화 방법 및 동기화된 문 블록을 사용하는 것보다 더 넓은 범위의 잠금 작업을 제공합니다.

2.java.util.concurrent 패키지

Lock 인터페이스

//试图获取锁.
void lock() 
 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
         
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()

ReentranLock 클래스

생성자 메서드

//创建一个 ReentrantLock 的实例.
ReentrantLock()          
//创建一个具有给定公平策略的 ReentrantLock实例.
ReentrantLock(boolean fair)

공정한 잠금: 다중 스레드는 잠금을 적용한 순서대로 잠금을 획득합니다.

불공정한 잠금: 다중 스레드는 잠금을 적용한 순서대로 잠금을 획득하지 않습니다. 즉, 먼저 잠금을 적용한 스레드가 잠금을 가장 먼저 획득하지 않을 수 있습니다.

공통 메소드 요약

//试图获取锁.   void lock() //如果当前线程未被中断,则获取锁.void lockInterruptibly() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁.boolean tryLock() //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁.  boolean tryLock(long timeout, TimeUnit unit) //试图释放此锁.    void unlock() //返回用来与此 Lock 实例一起使用的 Condition 实例.Condition newCondition() //如果此锁的公平设置为 true,则返回 true.boolean isFair() //返回正等待获取此锁的线程估计数.int getQueueLength()     //返回等待与此锁相关的给定条件的线程估计数.int getWaitQueueLength(Condition condition) //返回标识此锁及其锁定状态的字符串.String  toString()

Condition 인터페이스

//使当前线程在接收到信号前或被中断前一直保持等待状态.
void await()
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(TimeUnit为时间单位).
boolean await(long time, TimeUnit unit)
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(单位为毫秒).
long awaitNanos(long nanosTimeout)
 
//使当前线程在接收到信号前或被中断前或达到最后日期期限前一直保持等待状态.
boolean awaitUntil(Date deadline)
 
//唤醒一个在该Condition实例等待的线程.
void signal()
 
//唤醒所有在该Condition实例等待的线程.         
void signalAll()

Condition 인스턴스는 Lock 인스턴스의 조건 제어로 Lock 인스턴스에 바인딩됩니다.

Condition 인터페이스에서 선언된 메서드를 호출하기 전에 먼저 이 Condition과 관련된 잠금을 얻어야 합니다. 이러한 메서드가 호출된 후 이 조건과 관련된 잠금이 원자적으로 해제됩니다.

signal() 및 signalAll() 메서드가 호출된 후 활성화된 스레드는 wait() 메서드에서 반환되기 전에 잠금을 다시 획득해야 합니다.

사용 예:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 17:36
* @Description:
*/
public class TestReentranLock implements Runnable{

    /**
     * 可重入锁
     */
    private ReentrantLock reentrantLock = new ReentrantLock(true);

    /**
     * 锁条件
     */
    private Condition condition = reentrantLock.newCondition();

    /**
     * 业务处理
     */
    public void service(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取锁");
        reentrantLock.lock();
        System.out.println(threadName+":获取锁成功");
        try {
            System.out.println(threadName+":使当前线程等待,并释放锁资源。");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
            System.out.println(threadName+":释放锁");
        }
    }

    /**
     * 唤醒在该Condition实例等待的线程
     */
    public void signalAll(){
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();
    }

    @Override
    public void run() {
        service();
    }

    public static void main(String[] args) {

        TestReentranLock testReentranLock = new TestReentranLock();

        Thread threadA = new Thread(testReentranLock,"线程A");
        Thread threadB = new Thread(testReentranLock,"线程B");
        Thread threadC = new Thread(testReentranLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        testReentranLock.signalAll();

    }

}

공정한 잠금 실행 결과:

线程B:尝试获取锁
线程A:尝试获取锁
线程B:获取锁成功
线程C:尝试获取锁
线程B:使当前线程等待,并释放锁资源。
线程A:获取锁成功
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:释放锁
线程C:释放锁
线程A:释放锁

불공정한 잠금 실행 결과:

线程B:尝试获取锁
线程A:尝试获取锁
线程A:获取锁成功
线程C:尝试获取锁
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:获取锁成功
线程B:使当前线程等待,并释放锁资源。
线程A:释放锁
线程B:释放锁
线程C:释放锁

ReadWriteLock 인터페이스

//返回用于读取操作的锁.
Lock readLock()          
//返回用于写入操作的锁.
Lock writeLock()

재진입ReadWriteLock class

생성자 메소드

//创建一个ReentrantReadWriteLock实例.
ReentrantReadWriteLock()        
//创建一个具有给定公平策略的ReentrantReadWriteLock实例.
ReentrantReadWriteLock(boolean fair)

공통 메소드 요약

//返回用于读取操作的锁.
Lock ReentrantReadWriteLock。ReadLock。readLock()   
//返回用于写入操作的锁.
Lock ReentrantReadWriteLock。WriteLock。writeLock()
//返回等待获取读取或写入锁的线程估计数目.
int getQueueLength()
//如果此锁的公平设置为 true,则返回 true.
boolean isFair()
//返回标识此锁及其锁状态的字符串.
String toString()

ReadLock/WriteLock 정적 내부 클래스공통 메소드 요약

//试图获取锁.
void lock() 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
          
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()
 
//返回标识此锁及其锁状态的字符串.
String toString()

ReadLock은 조건을 지원하지 않기 때문에 ReadLock이 호출됩니다. newCondition() 메서드는 UnsupportedOperationException 예외를 발생시킵니다.

ReentrantReadWriteLock을 사용하는 읽기 잠금 및 쓰기 잠금은 읽기-읽기 공유, 쓰기-쓰기 상호 배제 및 읽기-쓰기 상호 배제를 따릅니다.

사용 예:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 18:04
* @Description:
*/
public class TestReentrantReadWriteLock implements Runnable{


    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);

    /**
     * 读锁
     */
    private Lock readLock = reentrantReadWriteLock.readLock();

    /**
     * 写锁
     */
    private Lock writeLock = reentrantReadWriteLock.writeLock();

    /**
     * 读取操作
     */
    public void reading(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取读锁");
        readLock.lock();
        System.out.println(threadName+":获取读锁成功");
        System.out.println(threadName+":释放读锁");
        readLock.unlock();
    }

    /**
     * 写入操作
     */
    public void writing(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取写锁");
        writeLock.lock();
        System.out.println(threadName+":获取写锁成功");
        System.out.println(threadName+":释放写锁");
        writeLock.unlock();
    }


    public static void main(String[] args) {
        TestReentrantReadWriteLock testReentrantReadWriteLock = new TestReentrantReadWriteLock();

        Thread threadA = new Thread(testReentrantReadWriteLock,"线程A");
        Thread threadB = new Thread(testReentrantReadWriteLock,"线程B");
        Thread threadC = new Thread(testReentrantReadWriteLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();
    }

}

공유 실행 결과 읽기:

@Overridepublic void run() {     
 //读读共享      
 reading();
}
线程A:尝试获取读锁
线程B:尝试获取读锁
线程A:获取读锁成功
线程A:释放读锁
线程C:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程B:获取读锁成功
线程B:释放读锁

읽기 잠금은 동시에 여러 스레드에서 획득할 수 있으므로 읽기 효율성을 향상시킬 수 있습니다( 읽기만 가능하지만 잠금을 해제할 필요는 없지만 쓰기 잠금 획득에 영향을 미칩니다.)

쓰기-쓰기 뮤텍스 실행 결과:

@Overridepublic void run() {  
    //写写互斥     
    writing();
}
线程A:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程C:尝试获取写锁
线程A:释放写锁
线程B:获取写锁成功
线程B:释放写锁
线程C:获取写锁成功
线程C:释放写锁

쓰기 잠금만 획득 가능 동시에 하나의 스레드로.

읽기-쓰기 상호 배제 실행 결과:

@Overridepublic void run() {      
   //读写互斥      
   writing();
  reading();
}
线程A:尝试获取写锁
线程C:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程A:释放写锁
线程A:尝试获取读锁
线程C:获取写锁成功
线程C:释放写锁
线程C:尝试获取读锁
线程B:获取写锁成功
线程B:释放写锁
线程B:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程A:获取读锁成功
线程A:释放读锁
线程B:获取读锁成功
线程B:释放读锁

읽을 때 쓸 수 없고, 쓸 때 읽을 수 없습니다. 즉, 읽기 잠금을 획득할 때, 쓰기 잠금이 스레드에 의해 유지되는 경우 이번에는 쓰기를 기다립니다. 잠금이 해제됩니다. 쓰기 잠금을 획득할 때 스레드가 읽기 잠금을 보유하고 있으면 읽기 잠금이 해제될 때까지 기다리며 쓰기 잠금은 유지되지 않습니다.

3. Java의 잠금 분류

Java의 잠금은 잠금의 특성에 따라 구분됩니다.

공정한 잠금/불공정한 잠금

공정한 잠금: 멀티 스레드는 잠금을 신청한 순서대로 잠금을 획득합니다.

불공정 잠금: 다중 스레드는 잠금을 적용한 순서대로 잠금을 획득하지 않습니다. 즉, 첫 번째 lock()이 있는 스레드가 잠금을 가장 먼저 획득하지 않습니다.

ReentranLock, ReentrantReadWriteLock의 경우 구축 방식을 통해 공정한 잠금인지 불공정한 잠금인지 설정할 수 있습니다.

동기화 키워드의 경우 불공정 잠금입니다.

공유 잠금/독점 잠금

공유 잠금: 여러 스레드가 동시에 잠금을 보유할 수 있음을 의미합니다. ReadLock의 경우 공유 잠금입니다.

배타적 잠금: 동시에 하나의 스레드만 잠금을 보유할 수 있음을 의미합니다. ReentranLock, WriteLock 및 동기화의 경우 배타적 잠금입니다.

낙관적 잠금/비관적 잠금

낙관적 잠금과 비관적 잠금은 특정 잠금 특성이 아니라 동시성을 볼 때의 관점입니다.

낙관적 잠금: 동시 작업이 데이터 무결성에 영향을 미치지 않는다고 믿기 때문에 잠금이 필요하지 않습니다.

비관적 잠금: 동시 작업이 데이터 무결성에 확실히 영향을 미칠 것이라고 믿기 때문에 잠금을 수행해야 합니다.

읽기 작업은 낙관적 잠금에 적합합니다. 즉, 잠금이 수행되지 않아 데이터 읽기 효율성을 향상시킬 수 있습니다.

쓰기 작업은 비관적 잠금에 적합합니다. 즉, 잠금을 수행해야 합니다.

세그먼트 잠금

세그먼트 잠금은 잠금의 세분성을 개선하여 동시 작업을 제어하는 ​​잠금 설계를 의미합니다. Java ConcurrentHashMap의 세그먼트는 분할 잠금 작동 설계를 통해 동시성을 달성합니다.

바이어스 잠금/경량 잠금/헤비웨이트 잠금

바이어스 잠금, 경량 잠금, 헤비웨이트 잠금은 모두 잠금의 다양한 상태를 나타내며 동기화 키워드에 사용됩니다.

편향된 잠금: 동기화된 메서드 또는 동기화된 명령문 블록이 항상 하나의 스레드에 의해 유지됨을 의미합니다. 이때 잠금 상태는 편향된 잠금이므로 스레드가 잠금을 획득하는 비용이 줄어듭니다.

경량 잠금: 잠금 상태가 바이어스 잠금인 경우 다른 스레드에서 액세스하면 다른 스레드가 회전하여 잠금을 획득하려고 시도하며 잠금 상태는 경량 잠금입니다.

Spin은 특정 횟수를 반복하여 잠금을 획득하려고 시도합니다. 이 방법은 스레드를 차단하지 않으며 CPU 성능을 소모한다는 점입니다.

중량 잠금: 잠금 상태가 경량 잠금일 때 회전 후 다른 스레드가 잠금을 획득하지 못한 경우 잠금 상태는 중량 잠금이고 다른 스레드는 차단 상태로 들어가 성능이 저하됩니다.

잠금 상태가 바이어스 잠금일 때 성능이 가장 높고, 잠금 상태가 헤비급 잠금일 때 성능이 가장 낮습니다.

위 내용은 Java의 잠금이란 무엇입니까? Java의 잠금에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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