java锁

 Lock锁

          手动挡锁,手动加锁放锁 Lock lock = new  ReentrantLock 是可重入锁。解锁使用try块中的finally更为合适lock.uplock

          Condition con = ReentrantLock.newCondition()等待队列,等待拿锁,获得锁 Lock.lock   释放锁 Lock.uplock。

 con.await()等于wait()con.signal()等于notify()唤醒线程

        线程阻塞   LcokSupport.park()  不需要锁直接阻塞 ;       唤醒线程 LcokSupport.unpark(线程名字)随意唤醒(相当于如果阻塞给当前线程一个0标识他            就阻塞了,唤醒就是把0该成1,可以提前该,这样他就不阻塞了),  普通的阻塞等待,是在一个队列中进行等待的,很难指定某某线程醒过来

         线程门栓 CountDownLatch(N)让一个线程去等待N个线程执行完,每执行完一个线程(线程最后一个方法是 CountDownLatch.countDown())N就会减一

  在等待线程上需要加一个CountDownLatch.await(),这个方法表示,我一直阻塞需要等CountDown Latch(N)中的N变为0是开始执行

Volatile()

        保证线程可见性:

                    线程1,线程2,线程3,更改一个变量会放到公共区域里面去,修改后的值,并让线程高速缓存中的变量失效,

                    如果要操作变量,就需要去主存中取

          禁止指令重排序:

                   通过内存屏障实现,volatile会在每一步操作的后面加上一个屏障,让下一步操作看不到,这样虚拟机就不会进行重排,那么指令就会挨个执行

                   指令重排例子,假如你创建一个单例模式,双重验证,如果此单例模式没有使用Volatie()

      当线程1进来的时候第一道验证发现单列对象没有被创建,那么就拿锁开始创建对象,


       (创建对象分3步,第一步申请空间创建对象,第二部初始化,第三部指向堆内存,

       本来指向堆内存这个操作是第三步执行的,但是虚拟机发现,你有没有初始化跟我指向堆内存有什么关系,于是就可能会发生1,3,2)

       线程2进来的时候,线程一没有赋上值, 且线程之间不可见,也就是说线程二不知道线程一已经创建好单例对象了,所以线程二也会去抢锁,

        线程二在得到锁之后,发现已经有对象了,就不走if语句,直接拿着这个对象用,但此时线程一只走了1,3这两步,那么线程二从对象中什么都拿不到

 

(关于线程中变量的自增)

CAS(AtomicLong(要修改的值))可以做自增操作,无锁也能保证线程安全;Atomic包

LongAdder:分段锁,一万个线程的话,给你分成4份锁,最后把结果加起来

 CyclicBarriber:相当于一个栅栏满多少线程给你放行

这是一个线程

Runnable maaa = -> System.out.println("计算总帐");

 CyclicBarriber  cyclicBarriber = new  CyclicBarriber(3,maaaa);

这就代表我(maaaa)要等 3 个线程执行完我在开始执行

或者

也可以这样说,什么时候线程等待的有数量到3个了,我(maaaa)在开始执行

线程1,2,3,最后一个方法是 cyclicBarriber.await();

在主线程里调用 cyclicBarriber.reset(),代表我(maaa)在需要 3 个线程,我在执行一遍

//我有一百个线程但是我只允许2个线程同时运行,第二个参数公平的(公平就是不允许插队,轮到谁谁运行)
Semaphore s = new Semaphore(2,true);
s.acquire()s.release()



读写锁
 static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//读锁
 static Lock reafLock = readWriteLock.readLock();
 //写锁
 static Lock writeLock = readWriteLock.writeLock();

 

 
posted @ 2023-09-01 12:01  一个有理想的猿  阅读(28)  评论(0)    收藏  举报