并发包基本介绍
简单解释一下J.U.C,是JDK中提供的并发工具包,。里面提供了很多并发编程中很常用的实用工具类,比如atomic原子操作、比如lock同步锁、fork/join、CountDownLatch(信号量)、Semaphore (计数器)等。
Lock锁基本的实现
void lock() ---获取锁 如果没有获取到锁则阻塞等待。
void lockInterruptibly --- 和lock一样 但是可以阻塞线程 可以中断
tryLock()---非阻塞式获取锁,如果获取到锁则返回true,没有获取到锁返回false
tryLock(timeout, TimeUnit timeUnit)--- 带有超时时间获取锁
void unlock()---释放锁
锁具有的特性
悲观锁:
悲观锁比较悲观,当多个线程对同一行数据实现修改的时候,最后只有一个线程才能修改成功,只要谁能够对获取该到行锁则其他线程时不能够对该数据做任何修改操作,且是阻塞状态。 比如for update 或者事务开启了事务但是没有提交事务。
乐观锁:
乐观锁比较乐观,通过预值或者版本号比较,如果不一致性的情况则通过循环控制修改,当前线程不会被阻塞,是乐观,效率比较高。
公平与非公平锁:
公平锁:就是比较公平,根据请求锁的顺序排列,先来请求的就先获取锁,后来获取锁就最后获取到, 采用队列存放 类似于吃饭排队。
非公平锁:不是根据根据请求的顺序排列, 通过争抢的方式获取锁。
New ReentramtLock()(true)---公平锁
New ReentramtLock()(false)---非公平锁
独占锁与共享锁
独占锁:在多线程中,只允许有一个线程获取到锁,其他线程都会等待。
共享锁:多个线程可以同时持有锁,例如ReentrantLock读写锁。读读可以共享、
写写互斥、读写互斥、写读互斥。
锁的可重入性
在同一个线程中锁可以不断传递的,可以直接获取。
lock与synchronized区别
Lock基于AQS封装的锁 结合CAS实现
Synchronized是基于C++虚拟机封装
Lock公平锁与非公平锁
FairSync ---公平锁
NonfairSync ---非公平锁
父类都是 AbstractQueuedSynchronizer
Lock底层实现原理
AQS+LockSupport+Cas实现
LockSupport用法
LockSupport可以挂起或者唤醒线程 是UnSafe类实现的,
park()方法会阻塞当前线程
LockSupportApi
public static void park()---阻塞当前线程
public static void unpark(Thread thread)---恢复当前线程
LockSupport与Wait/notify区别
private static Object lockObject = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lockObject) {
try {
System.out.println("start");
lockObject.wait();
System.out.println("end");
} catch (Exception e) {
}
}
}).start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("notify");
synchronized (lockObject) {
lockObject.notify();
}
} |
public class Test013 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("start");
LockSupport.park();//
System.out.println("end");
});
t1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
t1.interrupt();
// System.out.println("主线程唤醒子线程");
// LockSupport.unpark(t1);
}
} |
纯手写Lock锁
public class MtMayiktLock {
// 0和1 0没有获取到锁,1表示获取到锁
private volatile int state;
private volatile AtomicInteger atomicState = new AtomicInteger(0);
// 获取锁的线程
private transient Thread exclusiveOwnerThread;
private ConcurrentLinkedDeque<Thread> waitDequeThrad = new ConcurrentLinkedDeque<Thread>();
public void lock() {
// if (compareAndSet(0, 1)) {
// this.exclusiveOwnerThread = Thread.currentThread();
// }
if (acquire()) {
return;
}
// 没有获取到情况下呢
final Thread currentThread = Thread.currentThread();
waitDequeThrad.add(currentThread);
for (; ; ) {
if (acquire()) {
return;
}
//当前线程变为阻塞,同时释放CPU执行权
LockSupport.park(currentThread);
}
}
public void unlock() {
if (exclusiveOwnerThread != Thread.currentThread()) {
new RuntimeException("不是当前线程来释放");
}
if (compareAndSet(1, 0)) {
// 唤醒线程
Thread peekThread = waitDequeThrad.poll();
this.exclusiveOwnerThread = null;
LockSupport.unpark(peekThread);
}
}
public boolean compareAndSet(int expect, int updat) {
return atomicState.compareAndSet(expect, updat);
}
private boolean acquire() {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSet(0, 1)) {
this.exclusiveOwnerThread = Thread.currentThread();
return true;
}
}
return false;
}
public int getState() {
return atomicState.get();
}
}
总结:lock是一个接口它需要是java代码的实现, ReentrantLock是lock的一个实现类,它内部抽象类Sync继承了AQS抽象类,用的是AQS的方法实现的
每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!! |
|