>JUC ? 就是Java API 中这三个包的简称:
>atomic 包
CAS:compare and swap ?要实现原子性操作
这是一种原子性操作,这是一种原子性赋值,
比如原来的 ++i ,现在对 i 进行原子性加一,从Java5之后就有了这个原子性操作,主要借助unsafe类(源码无法查看),Java为我们封装了一些类:
在atomic 包中
之前的例子改一下:
public class TestAtomic {
V v = new V();
public static void main(String[] args) {
TestAtomic ta = new TestAtomic();
ta.go();
}
private void go() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 10000; j++) {
v.add();
}
}
}).start();
}
while (Thread.activeCount() > 1) {
}
System.out.println(v.ai.get());
}
class V {
//public int i = 0;
public AtomicInteger ai=new AtomicInteger();
public void add() {//原本在这个地方加个锁,将整个方法锁住了,悲观锁(重量级锁)
//如果i++ 变成原子性的就没必要在外部加锁了
//i++;
ai.getAndIncrement();
}
}
}
>locks 包
1.重入锁基本使用:
public class TestLock {
public static void main(String[] args) {
new TestLock().go();
}
public void go() {
V v = new V();
new Thread(new Runnable() {
public void run() {
while (true) {
v.printString("AAAAAAAAAAAAAA");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
v.printString("BBBBBBBBBBBBBB");
}
}
}).start();
}
class V {
// 使用Lock 代替 synchronized
ReentrantLock lock = new ReentrantLock();
public void printString(String str) {
try {
lock.lock();
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i));
}
System.out.println();
} catch (Exception e) {
} finally {
// 为了确保锁可以被释放掉
lock.unlock();
}
}
}
}
2.条件锁:使用条件锁实现线程轮询
public class TestConditionLock {
V v = new V();
public static void main(String[] args) {
TestConditionLock t = new TestConditionLock();
t.go();
}
private void go() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
v.f1();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
v.f2();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
v.f3();
}
}
}).start();
}
class V {
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
int token = 1;
public void f1() {
lock.lock();
try {
while (token != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
token = 2;
System.out.println(Thread.currentThread().getName() + "--f1");
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void f2() {
lock.lock();
try {
while (token != 2) {
try {
condition2.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
token = 3;
System.out.println(Thread.currentThread().getName() + "--f2");
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void f3() {
lock.lock();
try {
while (token != 3) {
try {
condition3.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
token = 1;
System.out.println(Thread.currentThread().getName() + "--f3");
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
3.读写锁:
读写锁分为读锁和写锁。多个读锁之间不互斥、读锁和写锁之间互斥、写锁和写锁之间互斥。这一功能很重要,对并发读取提高了性能。
读写锁使用到了JUC中的ReentrantReadWriteLock类:
/**
* 测试读写锁: 1.有个地方存东西 2.提供读和写两个方法,对这两个地方进行操作 3.开启多个线程,有读,有写 4.证明读的时候可以读,写的时候不能其他操作
*/
public class TestReentrantReadWriteLock {
public static void main(String[] args) {
TestReentrantReadWriteLock t = new TestReentrantReadWriteLock();
t.go();
}
Data d = new Data();
Random r = new Random();
private void go() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
d.write(r.nextInt(1000));
}
}).start();
}
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
d.read(r.nextInt(999));
}
}).start();
}
}
class Data {
List<Integer> list = new ArrayList<>();
{
for (int i = 0; i < 1000; i++) {
list.add(i);
}
}
// 创建读写锁
ReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
public void read(int index) {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "进入读方法");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int i = list.get(index);
System.out.println(Thread.currentThread().getName() + "读到数据" + i);
System.out.println(Thread.currentThread().getName() + "读取完毕");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
readLock.unlock();
}
}
public void write(int data) {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "进入写方法");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.add(data);
System.out.println(Thread.currentThread().getName() + "写入完毕");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
}
}
显示:
Thread-0进入写方法
Thread-0写入完毕
Thread-1进入写方法
Thread-1写入完毕
Thread-2进入写方法
Thread-2写入完毕
Thread-3进入读方法
Thread-4进入读方法
Thread-5进入读方法
Thread-6进入读方法
Thread-7进入读方法
Thread-4读到数据403
Thread-5读到数据276
Thread-5读取完毕
Thread-7读到数据98
Thread-7读取完毕
Thread-6读到数据628
Thread-6读取完毕
Thread-3读到数据258
Thread-3读取完毕
Thread-4读取完毕
数据库中有表级别锁,行级锁,如何实现?思考。
单例模式中的同步代码块如何取代:
先看API实例:
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
改造一下单例:
public class Book {
private static Book instance = null;
private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public static Book getInstance() {
try {
rwl.readLock().lock();
if (instance == null) {
rwl.readLock().unlock();
rwl.writeLock().lock();
if (instance == null) {
instance = new Book();
}
rwl.readLock().lock();
rwl.writeLock().unlock();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
return instance;
}
}