多线程学习笔记-4

LockSupport

和wait,notify区别

wait,notify只能在同步代码中使用,lockSupport没有这个限制。lockSupport可以精准作用于某个线程,而notify只能是随机的某个线程。lockSupport不会产生死锁

中断

和stop的区别

stop是线程实例方法,调用后线程被强制终止执行,同时已经获得的锁也会被释放,可能造成数据不一致,逻辑不完整等不可预料的问题。而中断只是发送中断请求,也就是设置中断标志,至于是否真的要停止运行,取决于线程自己

isInterrupted

返回中断标志

interrupt

设置中断标志

interrupted

返回中断标志并设置为false

AQS

基于AQS实现可重入独占锁

class MyLock{
    private final Sync sync=new Sync();
    static class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            if(getExclusiveOwnerThread()==Thread.currentThread()){
                setState(getState()+1);
                return true;
            }
            if (getState()==0&&compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            if(getExclusiveOwnerThread()!=Thread.currentThread())throw new IllegalMonitorStateException();
            int c=getState()-arg;
            if(c==0){
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return c==0;
        }
    }
    public void lock(){
        sync.acquire(1);
    }
    public void unlock(){
        sync.release(1);
    }
}
public class Main{
    public static void main(String[] args) throws InterruptedException {
        MyLock myLock = new MyLock();
        int[] a={0};
        Thread t=new Thread(()->{
            for (int i = 0; i < 10000000; i++) {
                myLock.lock();
                a[0]++;
                myLock.unlock();
            }
        });
        t.start();
        for (int i = 0; i < 10000000; i++) {
            myLock.lock();
            a[0]++;
            myLock.unlock();
        }
        t.join();
        System.out.println(a[0]);
    }
}

锁

乐观锁&悲观锁

乐观锁和悲观锁是数据库中引入的名词,但是在java并发包中也引入了类似思想。

悲观锁认为多线程数据处理时,数据容易被修改,进行数据处理前需要获得排它锁,如果获取失败,则说明数据正在被其他线程处理,从而会抛出异常或者等待,如果获取成功则进行处理,然后释放锁

乐观锁认为数据处理一般不会冲突,在访问数据前不加排它锁,而在数据更新提交时检查数据是否冲突,采用了类似CAS的思想

悲观锁的实现往往依靠数据库的锁机制实现,而乐观锁并不需要数据库的锁机制,一般在表中添加version字段实现,乐观锁直到提交时才锁定,所以不会产生死锁。

数据库update操作是原子的

公平锁&非公平锁

公平锁指的是多个线程竞争锁时,根据时间顺序,先来的先获得锁,而非公平锁则不一定,后来的可能先获得锁。ReentrantLock默认是非公平锁,除非必要,否则使用非公平锁,因为公平锁会性能差一些

独占锁和共享锁

独占锁保证同一时间只能有一个线程获得锁,ReentrantLock就是独占锁。而共享锁可以让多个线程在同一时间获得同一个锁,ReadWriteLock是共享锁,它同一时刻运行多个线程读操作。

独占锁是悲观锁,每次访问资源都加锁,限制了并发访问性能,因为读不会影响数据一致性。共享锁是乐观锁。

可重入锁

当一个线程获得独占锁后,再去获取该锁,如果不被阻塞,这个锁就是可重入锁。synchronized是可重入锁。可重入锁内部,维护了一个线程标识,用来标识锁被哪个线程占用,同时有一个计数器。当锁被某个线程获得时,计数器置为1,如果被该线程再次获取,计数器+1,释放时-1,如果计数器为0,则将线程标识置为null,这时阻塞的线程会被唤醒来竞争锁

自旋锁

当线程获取自旋锁失败时,不会立刻阻塞自己,不放弃cpu使用权,继续多次尝试获取(jvm默认10次),直到成功或者超过次数。可以减少上下文切换和线程调度的开销,但是会增加cpu的使用时间。

posted @ 2021-04-24 20:22  我吃水煮虾  阅读(79)  评论(0)    收藏  举报