锁的公共父类接口
/**
* Created by zongx on 2019/10/9.
*/
public interface ThreadLock {
public void lock();
public void unlock();
}
自旋和阻塞的区别:
自旋——线程反复检查锁变量是否可用。无线程上下文切换
阻塞——让处理器去执行其他的可执行的线程。有线程上下文切换
自旋锁通过Atomic的CAS实现
1.1 浅析CompareAndSet(CAS):
AtomicInteger类compareAndSet通过原子操作实现了CAS操作,最底层基于汇编语言实现。
CAS是Compare And Set的一个简称,如下理解:
1,已知当前内存里面的值current和预期要修改成的值new传入
2,内存中AtomicInteger对象地址对应的真实值(因为有可能别修改)real与current对比,
相等表示real未被修改过,是“安全”的,将new赋给real结束然后返回;不相等说明real已经被修改,结束并重新执行1直到修改成功
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
重点看一下valueoffset
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
在生成一个AtomicInteger对象后,可以看做生成了一段内存,对象中各个字段按一定顺序放在这段内存中,字段可能不是连续放置的,
unsafe.objectFieldOffset(Field f)这个方法准确地告诉我"value"字段相对于AtomicInteger对象的起始内存地址的字节相对偏移量。
private volatile int value;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
value是一个volatile变量,不同线程对这个变量进行操作时具有可见性,修改与写入操作都会存入主存中,并通知其他cpu中该变量缓存行无效,保证了每次读取都是最新的值
/**
* Atomically update Java variable to <tt>x</tt> if it is currently
* holding <tt>expected</tt>.
* @return <tt>true</tt> if successful
*/
public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);
总的来说,Atomic实现了高效无锁(底层还是用到排它锁(native方法),不过底层处理比java层处理要快很多)与线程安全(volatile变量特性),CAS一般适用于计数;多线程编程也适用,多个线程执行AtomicXXX类下面的方法,当某个线程执行的时候具有排他性,在执行方法中不会被打断,直至当前线程完成才会执行其他的线程。
1.2 代码实现
package lock.spinlock;
import lock.ThreadLock;
import java.util.concurrent.atomic.AtomicReference;
/**
* Created by zongx on 2019/10/8.
* 自旋锁
* AtomicInteger类compareAndSet通过原子操作实现了CAS操作,最底层基于汇编语言实现。
* CAS是Compare And Set的一个简称,如下理解:
* 1,已知当前内存里面的值current和预期要修改成的值new传入
* 2,内存中AtomicInteger对象地址对应的真实值(因为有可能别修改)real与current对比,
* 相等表示real未被修改过,是“安全”的,将new赋给real结束然后返回;不相等说明real已经被修改,结束并重新执行1直到修改成功
*
*/
public class SpinLock implements ThreadLock {
private AtomicReference<Thread> cas = new AtomicReference<Thread>();//进行自选的主体
public void lock() {
Thread currentThread = Thread.currentThread();//锁的关键部位,通过对当前线程的CAS进行操作
//实际值,初始是null
while(!cas.compareAndSet(null,currentThread)){
}
}
public void unlock() {
Thread currentThread = Thread.currentThread();//锁的关键部位,通过对当前线程的CAS进行操作
cas.compareAndSet(currentThread,null);
}
}
//线程类与Demo类
package lock.spinlock;
import lock.ThreadLock;
import java.util.Random;
/**
* Created by zongx on 2019/9/20.
*/
public class MyThread extends Thread {
private ThreadLock lock;
public MyThread(String name , ThreadLock lock) {
super(name);
this.lock = lock;
}
@Override
public void run() {
lock.lock();
for (int i = 0; i < 3; i++) {
try {
Random random = new Random();
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "当前线程运行次数" + i);
}
lock.unlock();
}
}
package lock.spinlock;
/**
* Created by zongx on 2019/10/8.
*/
public class Demo {
public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
MyThread thread1 = new MyThread("Thread1", spinLock);
MyThread thread2 = new MyThread("Thread2", spinLock);
MyThread thread3 = new MyThread("Thread3", spinLock);
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果: