悲观锁:

每次获取数据的时候,都会担心数据被修改,所以每次获取数据的时候都会进行加锁,

确保在自己使用的过程中数据不会被别人修改,使用完成后进行数据解锁。

由于数据进行加锁,期间对该数据进行读写的其他线程都会进行等待。

 

-->Synchronized

-->写多读少

 

乐观锁:

每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,

但是在更新数据的时候需要判断该数据是否被别人修改过。

如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,

则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。

 

-->CAS(compare and set)

-->读多写少

 

悲观锁缺点:每一次加锁都会引起线程上下文的切换和线程调度,很影响系统运行性能

 

CAS:比较并修改

涉及到3个信息,一个存储位置V, 期望修改的值为A,获取原有数据为B(存储位置V获取)

步骤:

1、在存储位置V获取数据B

2、比较数据B和存储位置V的值是否相同:相同则将位置V的值修改为A

   如果不相等,循环到步骤1,直至相同修改完值退出

 

CAS存在问题:

ABA问题:-->解决:通过版本号解决

CPU资源消耗大

 

Synchronized重量级锁:锁的优化

无锁-》偏向锁-》轻量级锁-》重量级锁      --》锁可以升级但不能降级

 

----------

|  对象头  |

----------

| 对象本身 |

----------

|填充数据  |

----------

锁优化见资料-"Java多线程-锁的介绍"

 

ReentrantLock锁

 

该 java.util.concurrent.locks包路径下的锁

公平性锁、非公平锁

公平性锁:多个线程对资源的请求按照先来后到的顺序来有序获取资源

非公平性锁:多线程对资源的获取不是按照请求的顺序来进行资源获取的,需要进行抢夺是资源获取

 

 

无参构造函数可以看出:默认是非公平性锁

public ReentrantLock() {

    sync = new NonfairSync();

}

   

有参构造通过Boolean类型来确定使用是公平性锁还是非公平锁

public ReentrantLock(boolean fair) {

    sync = fair ? new FairSync() : new NonfairSync();

}

 

 

ReentrantLock是java中可重入锁的一个实现,一次只能有一个线程持有锁,也即所谓独占锁的概念

包含三个内部类:Sync、NonfairSync、FairSync,通过构造函数的参数来指定锁是否是公平的

常用方法

 

public class ReentrantLock implements Lock, java.io.Serializable {

 

private final Sync sync;

//默认是不公平锁

public ReentrantLock() {

    sync = new NonfairSync();

}

//参数fair决定,true为公平锁实现,false为非公平锁实现

public ReentrantLock(boolean fair) {

    sync = (fair)? new FairSync() : new NonfairSync();

}

 

public void lock() {

    sync.lock();

}

//不公平锁

public boolean tryLock() {

    return sync.nonfairTryAcquire(1);

}

//带超时时间的锁

public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {

    return sync.tryAcquireNanos(1, unit.toNanos(timeout));

}

public void unlock() {

    sync.release(1);

}

//是否有线程等待当前锁

public final boolean hasQueuedThreads() {

    return sync.hasQueuedThreads();

}

 

通过常用方法可知:

ReentrantLock都是把具体实现委托给内部类(Sync、NonfairSync、FairSync),

ReentrantLock的重入计数是使用AbstractQueuedSynchronizer的state属性的

state大于0表示锁被占用、等于0表示空闲,小于0则是重入次数太多导致溢出了.

ReentrantLock.Sync

 

static abstract class Sync extends AbstractQueuedSynchronizer {

 

abstract void lock();

 

//非公平获取,公平锁和非公平锁都需要这个方法

final boolean nonfairTryAcquire(int acquires) {

    final Thread current = Thread.currentThread();

    int c = getState();

    if (c == 0) {   //state == 0表示无锁

        //CAS确保即使有多个线程竞争锁也是安全的

        if (compareAndSetState(0, acquires)) {  //加锁成功

         //当前哪一个线程获取到锁,将线程信息记录到AQS里面 

            setExclusiveOwnerThread(current);   //设置当前持有锁的线程

            return true;                        //获取成功

        }

    } else if (current == getExclusiveOwnerThread()) {//当前线程正是锁持有者

            int nextc = c + acquires;

            if (nextc < 0) // 被锁次数上溢(很少出现)

                throw new Error("Maximum lock count exceeded");

            //锁被持有的情况下,只有持有者才能更新锁保护的资源

            setState(nextc);

            return true;

        }

        return false;

    }

    //释放

    protected final boolean tryRelease(int releases) {

        int c = getState() - releases;

        //只有锁的持有者才能释放锁

        if (Thread.currentThread() != getExclusiveOwnerThread())

            throw new IllegalMonitorStateException();

        boolean free = false;

        if (c == 0) {   //锁被释放

            free = true;

            setExclusiveOwnerThread(null);

        }

        setState(c);

        return free;

    }

    //当前线程是否持有锁

    protected final boolean isHeldExclusively() {

        return getExclusiveOwnerThread() == Thread.currentThread();

    }

 

    final ConditionObject newCondition() {

        return new ConditionObject();

    }

 

    //锁的持有者

    final Thread getOwner() {

        return getState() == 0 ? null : getExclusiveOwnerThread();

    }

    //加锁次数

    final int getHoldCount() {

        return isHeldExclusively() ? getState() : 0;

    }

    //是否上锁,根据state字段可以判断

    final boolean isLocked() {

        return getState() != 0;

    }

}

 

ReentrantLock.NonfairSync【非公平锁实现】

 

final static class NonfairSync extends Sync {

 

     // 执行lock,尝试立即闯入,失败就退回常规流程

    final void lock() {

        if (compareAndSetState(0, 1))   //比较并设置state,成功则表示获取成功

            setExclusiveOwnerThread(Thread.currentThread());//锁持有者

        else

            acquire(1);//获取失败,进入常规流程:acquire会首先调用tryAcquire

    }

 

    protected final boolean tryAcquire(int acquires) {

        return nonfairTryAcquire(acquires);

    }

}

 

acquire的实现(AbstractQueuedSynchronizer.java)

 

public final void acquire(int arg) {

    if (!tryAcquire(arg) &&

        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

 

ReentrantLock.FairSync(公平性锁实现)

 

final static class FairSync extends Sync {

    //见AbstractQueuedSynchronizer.java, 4.2节有

    final void lock() {

        acquire(1);

    }

 

    //公平版本的tryAcquire,除非是递归调用或没有等待者或者是第一个,否则不授予访问

    protected final boolean tryAcquire(int acquires) {

        final Thread current = Thread.currentThread();

        int c = getState();

        if (c == 0) {

            //是等待队列的第一个等待者

            if (isFirst(current) &&

                compareAndSetState(0, acquires)) {

                setExclusiveOwnerThread(current);   //加锁成功

                return true;

            }

        }

        //当前线程正是线程的持有者

        else if (current == getExclusiveOwnerThread()) {

            int nextc = c + acquires;

            if (nextc < 0)  //溢出

                throw new Error("Maximum lock count exceeded");

            setState(nextc);

            return true;

        }

        return false;

    }

}

 

isFirst的实现,即等待队列为空或者当前线程为等待队列的第一个元素

 

final boolean isFirst(Thread current) {

    Node h, s;

    return ((h = head) == null ||

            ((s = h.next) != null && s.thread == current) ||

            fullIsFirst(current));

}

 

lock() VS lockInterruptibly()

 

线程请求锁的几个方法:

lock():拿不到lock就不罢休,不然线程就一直block;

tryLock():马上返回,拿到lock就返回true,不然返回false;

tryLock(time):拿不到lock,就等一段时间,超时返回false;

 

线程在sleep或wait,join, 此时如果别的进程调用此进程的 interrupt()方法,

    此线程会被唤醒并被要求处理InterruptedException;

线程在运行中,则不会收到提醒。但是 此线程的 “中断标志”会被设置, 可以通过isInterrupted()查看并作出处理。

lockInterruptibly()和上面的第一种情况是一样的,线程在请求lock并被阻塞时,如果被interrupt,

则“此线程会被唤醒并被要求处理InterruptedException

 

线程间通信

 

Java.lang.Object

 

wait、notify、notifyAll

 

 

wait:让线程进入等待  -》线程状态转换中:running->waitting

notify:随机唤醒一个等待的线程

notifyAll:唤醒全部的线程

 

 

wait\notify\notifyAll必须作用与同一个对象,才能达到线程间通信的目的

wait

 

wait方法是Object的方法;

任意一个对象都可以调用wait方法,调用wait方法会将调用者的线程挂起,

使该线程进入一个叫wait的等待区域,直到其他线程调用同一个对象的notify方法才会重新激活调用者;

当wait方法被调用时,它会释放它所占用的锁标记,从而使线程所在对象中的synchronize数据可以被别的线程所使用,

所以wait()方法必须在同步块中使用,

notify()和notifyAll()方法都会对对象的“锁标记”进行修改,

所以都需要在同步块中进行调用,如果不在同步块中调用,虽然可以编译通过,

但是运行时会报IllegalMonitorStateException(非法的监控状态异常);

notify

 

notify()会通知一个处在wait()状态的线程;如果有多个线程处在wait状态,

他会随机唤醒其中一个;

notifyAll

 

notifyAll()会通知过所有处在wait()状态的线程,具体执行哪一个线程,

根据优先级而定;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值