public


在java中到底是值传递还是引用传递这个问题,我想大家都已经知道了,不知道的可以自行查阅资料呦。

首先age=10;传入changeValue1()的方法中,然后被赋值成20,因为基本的数据类型都是在栈中,首先main方法进栈,然后changeValue1()方法进栈,执行完changeValue1()方法之后,就出栈了,所以输出的还是10;对于changeValue2(),传递的是一个对象,对象不在栈中,实例化的是在堆中,会指向一个地址,传到方法中后,依然会指向这个地址,所以修改的是对象的值,所以输出的是发发,对于changeValue3()传递一个字符串,这个大家可能会犯错,因为是直接字符串的赋值,所以首先会在常量池中去找,常量池中没有的话,会把abc放进去,changeValue3()中,str="XXX",在常量池中还是没有,所以还会放进去XXX,所以changeValue3()方法和main方法分别指向了不同的值,所以输出abc,如下图:


Java 非公平锁 饥饿 hasqueueprecedessor_为什么synchronized是非公平锁


这下大家理解了吧,接下来说说java锁中公平锁和非公平锁。

java中的锁和mysql数据库的锁有一样的,也有不一样的,现在着重讲java中的锁。

首先大家应该了解ReentrantLock()是一个可重入锁。

Lock lock=new ReentrantLock();如果什么都不传,底层是不公平的,Lock lock=new ReentrantLock(true);这是公平的。


Java 非公平锁 饥饿 hasqueueprecedessor_为什么synchronized是非公平锁_02


Java 非公平锁 饥饿 hasqueueprecedessor_为什么synchronized是非公平锁_03


比如我们常见的Synchronized,它就是一个非公平的锁?为什么呢?因为在多线程的环境中,强占cpu的资源,假如有7个线程,第一次抢到的可能是3号线程抢到,3号线程释放锁之后,第二次这7个线程继续抢,有可能还是3号线程抢到,所以是非公平的锁。

对于ReentrantLock()来说,通过构造函数指定该锁是否是公平的,默认是非公平的。非公平锁的有点在于吞吐量比公平锁大。

公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放后,队列的第一个线程获取锁

非公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放锁后所有等待的线程同时去竞争

说到公平锁,就有必要谈谈什么是可重入锁。

可重入锁又名递归锁,最大的作用就是避免死锁,Synchronized和ReentrantLock都是非公平的可重入锁。

什么是可重入?

同一个线程可以反复获取锁多次,然后需要释放多次,指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,比如:进入method02()同步方法时会自动获取锁,


Java 非公平锁 饥饿 hasqueueprecedessor_公平锁_04


就好比进入你家家门,进家门是一把锁,进去之后,在进入你的卧室,会自动获取你卧室的锁,很形象吧。

下面说一下自旋锁,上篇文章也简单介绍过了,


Java 非公平锁 饥饿 hasqueueprecedessor_公平锁_05


自旋锁的好处:循环比较获取直到成功为止,没有类似wait的阻塞,自旋锁的核心就是比较并交换。来 手写一个自旋锁。


public class SpinLock {
    AtomicReference<Thread> atomicReference=new AtomicReference<Thread>();

    public static void main(String[] args) {
        SpinLock spinLock = new SpinLock();
        new Thread(()->{
            spinLock.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLock.myUnLock();
        },"AA").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            spinLock.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLock.myUnLock();
        },"BB").start();

    }
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"t come in");
        while(!atomicReference.compareAndSet(null,thread)){

        }


    }
    public void myUnLock(){
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+"t invoked myUnLock");
    }


}


以上都是锁的基本的知识,接下来的几篇文章会详细讲解以上的锁和独占锁(写锁)/共享锁(读锁)/互斥锁,后续几篇就先把并发这一块放放,先写点其他的知识,大家换换脑细胞,加油!