Java笔记:锁

Posted Bota5ky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java笔记:锁相关的知识,希望对你有一定的参考价值。

传统的Synchronized锁

Synchronized 通过为方法或代码块添加互斥锁,来保证线程安全性。 持有相同锁的多个线程,同一时间只有一个线程能够拿到锁并执行锁定的代码块或方法。

public synchronized void run() // do something 

Lock锁

接口Lock的实现类:

  • ReentractLock
  • ReentractReadWriteLock.ReadLock
  • ReentractReadWriteLock.WriteLock
public void run()
  lock.lock();
  try
    // do something 
   catch (Exception e) 
    e.printStackTrace();
   finally 
    lock.unlock();
  

非公平锁

非公平锁(Unfair Lock)是一种线程同步机制,与公平锁(Fair Lock)相对应。在多线程环境中,公平锁会按照线程的申请顺序来获取锁资源,即先到先得的原则。而非公平锁则不考虑线程的申请顺序,允许新来的线程插队获取锁资源,从而可能导致已经在等待的线程长期等待。

非公平锁的设计主要是为了提高系统的整体吞吐量和性能。由于公平锁要求按照申请顺序获取锁资源,如果一个线程获取锁资源的时间较长,那么其他已经准备好并且在等待的线程就必须一直等待。这样会导致线程频繁地从用户态和内核态之间切换,增加了上下文切换的开销,降低了系统的吞吐量。

相比之下,非公平锁允许新来的线程插队获取锁资源,避免了等待时间过长的情况,减少了线程的等待时间和上下文切换的开销,从而提高了系统的整体性能和吞吐量。然而,由于非公平锁的设计特点,可能会导致某些线程一直无法获取到锁资源,造成不公平现象。

选择使用公平锁还是非公平锁需要根据具体的场景和需求来决定。如果对线程的公平性要求较高,并且能够容忍一定的性能损失,可以选择公平锁。如果追求系统的整体性能和吞吐量,并且能够接受一些线程的不公平性,可以选择非公平锁。

Synchronized 和 Lock 的区别

https://xie.infoq.cn/article/4e370ded27e4419d2a94a44b3

JAVA并发编程学习笔记------锁顺序死锁

一、需求描述:

  将资金从一个账户转移到另一个账户。

二、程序实现:

(1)账户类:

public class Account {
    private long account;

    public Account(String user, long account) {
        this.account = account;
    }

    public Account() {
        super();
    }

    public long getAccount() {
        return account;
    }

    public void setAccount(long account) {
        this.account = account;
    }

    public void debit(long money){
        this.account -= money;
    }

    public void credit(long money){
        this.account += money;
    }
}

  (2)资产转移类:

public class TransMoney {
    private static final Object tieLock = new Object();
    public static void transferMoney(Account fromAccount,Account toAccount,long amount){
        synchronized (fromAccount){
            synchronized (toAccount){
                fromAccount.debit(amount);
                toAccount.credit(amount);
            }
        }
    }
}

  (3)测试类:

public class DemonstrateDeadLock {
    private static final int NUM_THREADS = 20;
    private static final int NUM_ACCOUNTS = 5;
    private static final int NUM_ITERATIONS = 1000000;

    public static void main(String[] args) {
        final Random rdn = new Random();
        final Account[] accounts = new Account[NUM_ACCOUNTS];

        for(int i=0;i<accounts.length;i++){
            accounts[i] = new Account();
        }

        class TransferThread extends Thread{
            public void run(){
                for(int i=0;i<NUM_ITERATIONS;i++){
                    int fromAccount = rdn.nextInt(NUM_ACCOUNTS);
                    int toAccount = rdn.nextInt(NUM_ACCOUNTS);

                    TransMoney.transferMoney(accounts[fromAccount],accounts[toAccount],rdn.nextInt(1000));
                }
            }
        }

        for(int i=0;i<NUM_THREADS;i++){
            new TransferThread().start();
        }
    }
}

  (4)解析:

上述程序容易形成死锁,原因在于多账户调用TransMoney.transferMoney时,存在锁顺序冲突,

解决方案是使用System.identityHashCode来定义锁的顺序,消除死锁的可能性,代码实现如下:

public static void transferMoney(final Account fromAccount,final Account toAccount,final long amount){
    class Helper{
        public void transfer(){
            fromAccount.debit(amount);
            toAccount.credit(amount);
        }
    }

    int fromHash = System.identityHashCode(fromAccount);
    int toHash = System.identityHashCode(toAccount);
    if(fromHash < toHash){
        synchronized (fromAccount){
            synchronized (toAccount){
                new Helper().transfer();
            }
        }
    }else if(fromHash > toHash){
        synchronized (toAccount){
            synchronized (fromAccount){
                new Helper().transfer();
            }
        }
    }else{
        synchronized (tieLock){
            synchronized (fromAccount){
                synchronized (toAccount){
                    new Helper().transfer();
                }
            }
        }
    }
}

 

以上是关于Java笔记:锁的主要内容,如果未能解决你的问题,请参考以下文章

Java:java学习笔记之锁机制的简单理解和使用

《深入理解Java虚拟机》笔记04 -- 并发锁

java锁学习笔记

java锁学习笔记

java线程笔记(锁线程通讯线程池)

java线程笔记(锁线程通讯线程池)