Java多线程互斥及其区别

在Java中,若要实现多线程对共享资源的互斥访问,可采用synchronized关键字或者Lock接口。


1、使用synchronized关键字

package com.day0303;

class MyThread implements Runnable{
    private int ticket = 10;
    public void run(){
        for(int i = 0; i < 20; i++){
            // 使用同步块来确保线程安全
            synchronized (this) {
                if(this.ticket > 0){
                    System.out.println("售票:ticket" + this.ticket--);
                }
            }
        }
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }
}

在上述代码里,synchronized (this)创建了一个同步块,保证同一时刻仅有一个线程能够进入该块操作共享资源ticket。

2、使用Lock接口

package com.day0303;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class MyThread implements Runnable{
    private int ticket = 10;
    private final Lock lock = new ReentrantLock();

    public void run(){
        for(int i = 0; i < 20; i++){
            // 获取锁
            lock.lock();
            try {
                if(this.ticket > 0){
                    System.out.println("售票:ticket" + this.ticket--);
                }
            } finally {
                // 释放锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }
}

在这段代码中,ReentrantLock是Lock接口的一个实现类。lock.lock()用于获取锁,lock.unlock()用于释放锁。为了保证锁一定会被释放,把释放锁的操作放在finally块中。
这两种方法都能实现多线程对共享资源的互斥访问,不过synchronized关键字使用起来更简便,而Lock接口则提供了更灵活的锁控制。

3、两种锁机制的区别

●语法和使用方式
        ▶ synchronized 关键字:是 Java 内置的同步机制,使用起来较为简洁,不需要手动释放锁。可以用于修饰方法或代码块。

// 同步方法
public synchronized void method() {
    // 方法体
}

// 同步代码块
synchronized (this) {
    // 代码块
}

        ▶Lock 接口:是 Java 并发包(java.util.concurrent.locks)中的一个接口,需要手动获取和释放锁。通常使用 ReentrantLock 类来实现。

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区代码
} finally {
    lock.unlock();
}

●锁的获取和释放
        ▶ synchronized 关键字:由 JVM 自动获取和释放锁。当线程进入同步方法或同步代码块时,JVM 自动获取锁;当线程退出时,JVM 自动释放锁。这种方式简单方便,但缺乏灵活性。
        ▶ Lock 接口:需要手动调用 lock() 方法获取锁,调用 unlock() 方法释放锁。为了确保锁一定会被释放,通常将 unlock() 方法放在 finally 块中。这种方式提供了更多的控制,例如可以尝试获取锁、定时获取锁等。

●锁的特性
        ▶ synchronized 关键字:是可重入锁、非公平锁。可重入意味着同一个线程可以多次获取同一把锁,而非公平锁表示线程获取锁的顺序是不确定的。
        ▶ Lock 接口:可以实现可重入锁、公平锁或非公平锁。ReentrantLock 类默认是非公平锁,但可以通过构造函数指定为公平锁。公平锁保证线程按照请求锁的顺序获取锁。

●锁的中断
        ▶ synchronized 关键字:不支持锁的中断。如果一个线程在等待获取锁,它会一直等待,直到获取到锁或抛出异常。
        ▶ Lock 接口:支持锁的中断。可以使用 lockInterruptibly() 方法获取锁,当线程在等待获取锁的过程中被中断时,会抛出 InterruptedException 异常。

●性能
        ▶ synchronized 关键字:在 JDK 1.6 之后进行了大量的优化,性能有了很大的提升。在大多数情况下,性能与 Lock 接口相当。
        ▶ Lock 接口:在高并发场景下,Lock 接口的性能可能会更好,因为它提供了更多的优化选项,例如锁的粒度控制、锁的超时机制等。

★ 综上所述,synchronized 关键字适用于简单的同步场景,而 Lock 接口适用于复杂的同步场景,需要更多的锁控制和灵活性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值