CAS
compare and set
cas(V, expected, newValue)
我们要修改V的值为newValue,如果它是我们期望的值expected,则修改,
否则重新比较或失败。
CAS是CPU层面的支持,不会被打断。
开发工作中,如果需要频繁地加synchronized锁,可以通过原子的Atomic类来实现,
这些Atomic开头的类的内部自动就带了锁,当然这些锁挺不是重量级synchronized锁,
而是通过CAS操作来实现的(号称无锁)。
AtomicInteger就是concurrent包下的一个原子的Integer类型,它是线程安全的。
基于CAS的锁
ReentrantLock可重入锁
package com.duohoob.jvm.thread.cas;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 可重入锁
*
* 注意:必须要手动释放锁
* @author yangwei
*
*/
public class ReentrantLockTest {
Lock lock = new ReentrantLock(true); // true代表公平锁,即当一个新的线程过来的时候,会进入阻塞队列等待,否则直接抢
void m1() {
// 加try-finally是为了保证异常情况下也能释放锁
try {
lock.lock(); // 相当于synchronized (this)锁住当前对象
for (int i = 0; i < 10; i++) {
System.out.print("m1:" + i); // 这里没有换行
m2(); // m2也持有当前对象的锁,如果能执行说明ReentrantLock是可重入的
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
void m2() {
try {
lock.lock();
System.out.println(); // 输出换行
} finally {
lock.unlock();
}
}
void m3() {
boolean locked = false;
try {
locked = lock.tryLock(3, TimeUnit.SECONDS); // 尝试申请锁,3秒之后没有拿到则不再阻塞,继续执行
System.out.println("m3 locked:" + locked);
} catch (Exception e) {
// TODO: handle exception
} finally {
if (locked) {
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLockTest rlt = new ReentrantLockTest();
new Thread(rlt::m1).start();
new Thread(rlt::m3).start();
}
}
输出
m1:0
m1:1
m1:2
m3 locked:false
m1:3
m1:4
m1:5
m1:6
m1:7
m1:8
m1:9
ReadWriteLock读写锁
package com.duohoob.jvm.thread.cas;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 读写锁
* @author yangwei
*
*/
public class ReadWriteLockTest {
static ReentrantLock lock = new ReentrantLock();
static ReadWriteLock rwLock = new ReentrantReadWriteLock();
static Lock readLock = rwLock.readLock(); // 共享锁,其它线程还可以加读锁,但是不能加写锁
static Lock writeLock = rwLock.writeLock(); // 排它锁,其它线程不可以加任何锁
static void read(Lock lock) {
try {
lock.lock();
Thread.sleep(1000);
System.out.println("read over!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
static void write(Lock lock) {
try {
lock.lock();
Thread.sleep(1000);
System.out.println("write over!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
// Runnable readR = ()-> read(lock); // 这种方式相当于synchronized,其它线程都会被阻塞
Runnable readR = ()-> read(readLock);
// Runnable writeR = ()->write(lock);
Runnable writeR = ()->write(writeLock);
for (int i = 0; i < 8; i++) {
new Thread(readR).start();
}
for (int i = 0; i < 2; i++) {
new Thread(writeR).start();
}
}
}
输出
read over!
read over!
read over!
read over!
read over!
read over!
read over!
read over!
write over!
write over!
如果传入ReentrantLock需要10秒以上才能输出。