锁的作用就是当一个线程持有锁的时候,其他线程都不能对锁定的共享变量进行操作,简而言之把并行操作变为串行操作。
用java如何实现,我们定义一个持有锁的标志,当一个线程持有锁的时候,把其他线程挂起,当这个持有锁的线程释放锁时,把其中一个的挂起的线程唤醒。
实现主要用到Unsafe的park方法挂起线程和unpark方法唤醒线程,java是不允许直接操作内存,所以这个类不能被直接引用,可以通过反射来获取权限。
锁之简单实现;
public class SimpleLock implements java.io.Serializable { /** * */ private static final long serialVersionUID = -8815596805585415733L; private volatile int state; private static final Unsafe unsafe; private static final long stateOffset; private volatile Thread ownerThread; private static final BlockingQueue<Thread> blockQueue; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); unsafe = (Unsafe) theUnsafe.get(null); stateOffset = unsafe.objectFieldOffset(SimpleLock.class.getDeclaredField("state")); blockQueue = new LinkedBlockingQueue<>(); } catch (Exception ex) { throw new Error(ex); } } private boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } private void setState(int state) { this.state = state; } private int getState() { return this.state; } public void lock() { /** * 当前线程获得锁,当前线程就运行,如果没有获得锁,当前线程就中断。 */ Thread current = Thread.currentThread(); if (compareAndSet(0, 1)) { ownerThread = current; } else { // 如果当前线程持有锁,且的它未完成任务,其他线程挂起,否则等待线程里面的其中一个线程获得锁 if (ownerThread == current) { // System.out.println(ownerThread.getState().toString()); if (ownerThread.getState() == Thread.State.TERMINATED) { setState(0); LockSupport.unpark(ownerThread); } } else { blockQueue.add(current); LockSupport.park(this); } } } public void unlock() { LockSupport.unpark(blockQueue.poll()); setState(0); } public static void main(String[] args) { class RunThread implements Runnable { private SimpleLock simpleLock = new SimpleLock(); int i = 0; @Override public void run() { simpleLock.lock(); for (int j = 0; j < 10; j++) { i++; System.out.println(String.format("ThreadName:%s,i:%d", Thread.currentThread().getName(), i)); } simpleLock.unlock(); } } RunThread runThread = new RunThread(); Thread t1 = new Thread(runThread); t1.start(); Thread t2 = new Thread(runThread); t2.start(); Thread t3 = new Thread(runThread); t3.start(); } }