import org.apache.log4j.Logger;
import sun.misc.Unsafe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by jz
* 2020/11/9.
*/
public class UnsafeAccess {
private static final String ANDROID = "THE_ONE";
private static final String OPEN_JDK = "theUnsafe";
private static Unsafe UNSAFE;
static {
Field field = null;
try {
field = Unsafe.class.getDeclaredField(OPEN_JDK);
} catch (NoSuchFieldException e) {
try {
field = Unsafe.class.getDeclaredField(ANDROID);
} catch (NoSuchFieldException e1) {
try {
Constructor<Unsafe> constructor = Unsafe.class.getDeclaredConstructor();
constructor.setAccessible(true);
UNSAFE = constructor.newInstance();
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e2) {
throw new Error(e2);
}
}
}
if (field != null){
field.setAccessible(true);
try {
UNSAFE = (Unsafe)field.get(null);
} catch (IllegalAccessException e) {
throw new Error(e);
}
}
}
private UnsafeAccess(){
}
public static Unsafe get(){
return UNSAFE;
}
}
class YYLock{
private static Logger logger = Logger.getLogger(UnsafeAccess.class.getClass());
private volatile int state = 0;
private static long stateoffset;
private static Unsafe unsafe;
static {
try {
unsafe = UnsafeAccess.get();
stateoffset = unsafe.objectFieldOffset(YYLock.class.getDeclaredField("state"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateoffset, expect, update);
}
private Thread holdThread;
public void setHoldThread(Thread thread){
this.holdThread = thread;
}
private ConcurrentLinkedQueue<Thread> threads = new ConcurrentLinkedQueue<>();
public void lock(){
for (;;){
logger.warn("------------------------------------------" + Thread.currentThread().getId() + "开始自旋!");
if (compareAndSetState(0, 1)){
logger.warn("------------------------------------------" + Thread.currentThread().getId() + "获取到了锁!");
this.setHoldThread(Thread.currentThread());
return;
} else {
logger.warn("------------------------------------------" + Thread.currentThread().getId() + "没有获取到锁!");
threads.add(Thread.currentThread());
LockSupport.park();
}
}
}
public void unlock(){
if (Thread.currentThread() == holdThread && compareAndSetState(1, 0)){
logger.warn("------------------------------------------" + Thread.currentThread().getId() + "释放了锁!");
LockSupport.unpark(this.threads.poll());
}
}
}
class LockThread implements Runnable{
private static Logger logger = Logger.getLogger(UnsafeAccess.class.getClass());
private CyclicBarrier cyclicBarrier;
private YYLockTest yyLockTest;
public LockThread(CyclicBarrier cyclicBarrier, YYLockTest yyLockTest){
this.cyclicBarrier = cyclicBarrier;
this.yyLockTest= yyLockTest;
}
@Override
public void run() {
logger.warn("------------------------------------------" + Thread.currentThread().getId() + "准备就绪!");
try {
cyclicBarrier.await();
yyLockTest.plus();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class YYLockTest{
private static Logger logger = Logger.getLogger(UnsafeAccess.class.getClass());
YYLock yyLock = new YYLock();
//
// ReentrantLock yyLock = new ReentrantLock();
int a = 5;
public void plus(){
yyLock.lock();
if (a > 0){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
a--;
logger.warn("------------------------------------------库存剩余:" + a);
} else {
logger.warn("------------------------------------------库存:" + a);
}
yyLock.unlock();
}
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
YYLockTest yyLockTest = new YYLockTest();
LockThread lockThread = new LockThread(cyclicBarrier, yyLockTest);
for (int i = 0; i < 10; i++){
Thread thread = new Thread(lockThread);
thread.start();
}
}
}
一.java中提供了常用的锁实现有以下两种
Synchronized与ReentrantLock, 这两种锁的区别是第一种是以java关键字形式,基于monitor实现的锁。这样的锁,我们无法控制加锁与解锁。
第二种是java-api级别的锁。这个锁,开发者可以通过lock()和unlock()来自由控制。
而这两种锁的性能在jdk1.6以后几乎没有什么太大的差别。另一点是ReentrantLock他有公平锁和非公平锁之分。所谓公平锁就是所有线程想获取锁,必须排队等待,而非公平锁就是如果此时正好有线程还没有加入等待队列,则让其插队,直接获取到锁。
二.ReentrantLock的实现原理(以公平锁举例)
1.猜想
如何才能实现一个锁?
1.让所有线程争抢执行一个原子操作,执行成功则获取到锁,执行失败则获取不到。
这里可以使用Unsafe类实现原子操作(CAS)
2.一个共享变量让所有线程可以看到他的值(volatile state)对他进行CAS操作。
3.如果获取不到锁,其他线程如何处理?
--1)放弃,直接返回失败
--2)排队等待,等待是一直让线程不停的去执行原子操作,看是否成功?还是让其挂起,等待获取到锁的线程执行成功后,通知他去执行原子操作,从而获取到锁?
我们知道让线程一直不停的执行命令是非常消耗CPU资源的,所以应该采用第二种方式。java提供了一个线程挂起和唤醒的工具类LockSupport。