java.util.concurrent.locks.Lock锁

記事のディレクトリ

ロック

(ロックなしで)チケットを販売する簡単な例を見てみましょう。

package demo1;

public class SaleTicketTest {
    
    
    public static void main(String[] args) {
    
    
        // lambda 表达式 ()表示run() 其中"()"中可以写明参数 ,->{} 表示 run后的代码块{}
        // 支持 lambda 表达式,必须是接口上有 @FunctionalInterface 注解
        // @FunctionalInterface 注解的接口,只能存在一个 抽象方法!

        Ticket ticket = new Ticket();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"C").start();

    }
}
class Ticket{
    
    
    private Integer num = 40;
    public void sale(){
    
    
        if(num > 0){
    
    
            num --;
            System.out.println(Thread.currentThread().getName()+"卖票,剩余:"+num+"张");
        }
    }
}

さらに数回実行すると、取得されるログ情報は次のようになります。
ここに画像の説明を挿入

注文が乱雑です!

JDK8の新機能:機能インターフェース@FunctionalInterfaceの使用方法

JDK 1.5之前的做法:

テイクsynchronizedロックします!

class Ticket{
    
    
    private Integer num = 40;
    public synchronized void sale(){
    
    
        if(num > 0){
    
    
            num --;
            System.out.println(Thread.currentThread().getName()+"卖票,剩余:"+num+"张");
        }
    }
}

JDK 1.5 之后的做法:
java.util.concurrent.locks.Lockクラスを使用して実装加锁および释放锁操作できます

package demo1;

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

public class SaleTicketTest3 {
    
    
    public static void main(String[] args) {
    
    
        // lambda 表达式 ()表示run() 其中"()"中可以写明参数 ,->{} 表示 run后的代码块{}
        // 支持 lambda 表达式,必须是接口上有 @FunctionalInterface 注解
        // @FunctionalInterface 注解的接口,只能存在一个 抽象方法!

        Ticket3 ticket3 = new Ticket3();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket3.sale();
            }
        },"A").start();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket3.sale();
            }
        },"B").start();
        new Thread(()->{
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket3.sale();
            }
        },"C").start();

    }
}

class Ticket3{
    
    
    private Integer num = 40;//目标数
    private Integer saleNum = 0; //卖出数

    // 可重入锁(最实用)
    // 调用无参构造,生成 “不公平锁”
    // 可以传递参数 ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();} true为公平锁
    // 不公平锁,性能更好,可以插队!
    Lock lock = new ReentrantLock();
    public void sale(){
    
    
        lock.lock(); //加锁
        //lock.tryLock();
        try {
    
    
            if(num > 0){
    
    
                num --;
                saleNum ++;
                System.out.println(Thread.currentThread().getName()+"卖票,共卖了"+saleNum+"张,剩余:"+num+"张");
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            lock.unlock();//释放锁
        }
    }
}

同期とロックの違い

  • Synchronizedはjavaキーワードであり、Lockはjavaの単なるクラスです。
  • Synchronizedはロックの状態を認識できませんが、Lockはロックが正常に取得されたかどうかを判断できます。
  • 同期されたロックと解放は自動的に行われますが、ロックは手動で行う必要があります。
  • 同期されたスレッドがブロックされている場合、他のスレッドは待機を続けますが、ロックは待機しない場合があります(lock.tryLock())。
  • 同期は、再入可能ロック、中断
    不能、不公平にすることができますロックは再入可能ロックにすることができ、中断するかどうかを判断でき、公平ロック/不公平ロックを選択できます。
  • 同期は、少量のコード同期の問題に適しています。ロックは、多数の同期コードに適しています。

おすすめ

転載: blog.csdn.net/qq_38322527/article/details/114600069