>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;
}
}