Java主流锁

Java主流锁,第1张

Java主流锁

 

 

 

1、公平锁,非公平锁

        公平锁:非常公平,不能够插队,必须先来后到

        非公平锁:非常不公平,可以插队(默认的都是非公平锁)

        

public ReentrantLock() {  //非公平锁,默认
        sync = new NonfairSync();
    }

public ReentrantLock(boolean fair) {//公平锁,new ReentrantLock(true),参数改为true时为公平锁
        sync = fair ? new FairSync() : new NonfairSync();
    }
2、可重入锁(递归锁)-------所有的锁,都是可重入锁

        概念:拿到了最外层的锁之后,就可以拿到了后面的锁(这是自动获得的)。举例:拿到了家门口的钥匙,就可以打开家里房间的门。

 synchronized版

package lin.lock;

import java.util.concurrent.TimeUnit;

//Synchronized==========================================================
public class ReenTrantLock_ {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.sms();
        },"A").start();

        

        new Thread(()->{
            phone.sms();
        },"B").start();


    }
}

class Phone{
    public synchronized void sms(){
        System.out.println(Thread.currentThread().getName()+" sms");
        call();     //这里也有锁
    }

    public synchronized void call(){
        System.out.println(Thread.currentThread().getName()+" call");
    }
}

执行结果: 

 

 lock版

package lin.lock;

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

//Lock锁==========================================================
public class ReenTrantLock_Demo02 {
    public static void main(String[] args) {
        Phone2 phone = new Phone2();

        new Thread(()->{
            phone.sms();
        },"A").start();
        

        new Thread(()->{
            phone.sms();
        },"B").start();


    }
}

class Phone2{
    Lock lock = new ReentrantLock();

    public  void sms(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+" sms");
            call();     //这里也有锁
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public  void call(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+" call");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

执行结果: 

 

细节问题:ReentrantLock版,当调用sms()这个方法时,拿到了lock.lock()这把锁,这时又调用了call()方法,此时又拿到call()的lock.lock()锁,然后lock.unlock()解锁,然后才会去执行sms()中的lock.unlock()解锁!(在lock锁中必须要配对,否则就会死锁

3、自旋锁(不断地去循环。遍历,迭代知道成功为止)

什么是自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

自己写一个基础的自旋锁,小测试:

package lin.lock;

import java.util.concurrent.atomic.AtomicReference;


public class SpinLockDemo01 {

    //Thread引用类型,默认的是null
    AtomicReference atomicReference = new AtomicReference<>();

    //加锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"------ myLock");

        //自旋锁
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }

    //解锁
    public void myUnLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"------ myUnLock");
        atomicReference.compareAndSet(thread,null);
    }
}
package lin.lock;

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

public class TestSpinLock {
    public static void main(String[] args) {
//        ReentrantLock lock = new ReentrantLock();
//        lock.lock();
//        lock.unlock();

        //底层就是CAS实现的自旋锁
        SpinLockDemo01 lock = new SpinLockDemo01();

        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"B").start();



    }
}

 

 注意:A线程进来之后,会先拿到这个锁,线程B必须等待。然后A线程自旋,等A线程解锁之后,B线程才有资格解锁。(因为A解锁之后才会释放,释放之后B才有机会进去拿到锁,然后再解锁)

4、死锁 

死锁是什么?

所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

死锁产生的4个必要条件? 产生死锁的必要条件:

互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。

死锁的例子

package lin.lock;

import java.util.concurrent.TimeUnit;

public class DeadLockDemo01 {
    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";

        new Thread(new MyThread(lockA,lockB),"T1").start();
        new Thread(new MyThread(lockB,lockA),"T2").start();
    }
}

class MyThread implements Runnable{

    private String lockA;
    private String lockB;

    public MyThread(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized(lockA){
            System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>"+lockB);

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>"+lockA);
            }
        }
    }
}

结果:

遇到死锁,如何解决问题(因为在控制台中,没有显示任何的异常,只是单纯的卡着程序不懂而已,如何排查错误!!!)

  1.  使用 jps -l 定位进程号(前面的一串数字就是进程号)
  2. 使用 jstack 进程号 找到死锁问题

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5522977.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-13
下一篇 2022-12-13

发表评论

登录后才能评论

评论列表(0条)

保存