chapt3 JDK併發包
1. 重入鎖 (ReentrantLock)
優點:lockInterruptibly可以被中斷,而且支持本線程反覆加鎖,注意點是加鎖與釋放鎖必須配對
例子:驗證中斷的情況,t1線程佔據鎖並且不釋放,t2由此被掛起,無法繼續執行,那麼可以通過中斷的方式,使得t2繼續執行(代價是t2部分業務代碼無法繼續執行)
public class LockTest {
private ReentrantLock reentrantLock = new ReentrantLock();
public void doTest() throws InterruptedException {
Thread t1 = new Thread(new MyInterruptRunnalbe("thread-1"));
t1.start();
Thread.sleep(1000);
Thread t2 = new Thread(new MyInterruptRunnalbe("thread-2"));
t2.start();
Thread.sleep(1000);
t2.interrupt();
}
class MyInterruptRunnalbe implements Runnable {
private String name ;
public MyInterruptRunnalbe(String name) {
this.name = name;
}
@Override
public void run() {
try {
reentrantLock.lockInterruptibly();
int i = 0;
while(true) {
i++;
}
}
catch (Exception e) {
if(e instanceof InterruptedException) {
System.out.println(name+" has been interrupt");
}
e.printStackTrace();
}
}
}
}
打印輸出如下:
thread-2 has been interrupt
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at com.jeyawn.test.LockTest$MyRunnalbe.run(LockTest.java:35)
at java.lang.Thread.run(Thread.java:748)
如果我們用lock,那麼則不會響應中斷。
tryLock,如果可以獲取鎖,那麼立刻返回true,反之返回false。
另外,使用synchronized,那麼則無法打到這個效果,
2. Condition
例子講解:
public class LockTest2 implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
@Override
public void run() {
try {
lock.lock();
condition.await();
System.out.println("Thread is going on");
while(true);
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
System.out.println("unlock it.....");
lock.unlock();
}
}
public void doTest() throws InterruptedException {
LockTest2 lockTest2 = new LockTest2();
Thread t1 = new Thread(lockTest2);
t1.start();
Thread.sleep(2000);
lock.lock();
System.out.println("I get the lock...");
condition.signal();//如果這裏不發信號,則線程無法被喚醒
System.out.println("signal has been send...");
lock.unlock();//如果這裏不釋放鎖,則線程也無法得到鎖繼續執行
}
}
輸出打印如下:
I get the lock...
signal has been send...
Thread is going on
3. 信號量
4. 讀寫鎖 Reentrant Read WriteLock
public class ReadWriteLokTest {
private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private static ReadLock readLock = reentrantReadWriteLock.readLock();
private static WriteLock writeLock = reentrantReadWriteLock.writeLock();
public void doTest() {
Thread [] threads = new Thread[5];
for(int i = 0; i < 5; i++) {
threads[i] = new Thread(new Runnable() {
private String threadName;
@Override
public void run() {
readLock.lock();
System.out.println(Thread.currentThread().getName()+" get lock in read");
try {
Thread.sleep((int)(Math.random()*10));
}
catch (Exception e) {
e.printStackTrace();
}
finally {
System.out.println(Thread.currentThread().getName()+" finished read");
readLock.unlock();
}
}
});
threads[i].setName(String.valueOf(i));
threads[i].start();
}
Thread []writeThreads = new Thread[3];
for(int i = 0; i < 3; i++) {
writeThreads[i] = new Thread(new Runnable() {
private String threadName;
@Override
public void run() {
writeLock.lock();
System.out.println(Thread.currentThread().getName()+" get lock in write");
try {
Thread.sleep((int)(Math.random()*10));
}
catch (Exception e) {
e.printStackTrace();
}
finally {
System.out.println(Thread.currentThread().getName()+" finished write");
writeLock.unlock();
}
}
});
writeThreads[i].setName(String.valueOf(i));
writeThreads[i].start();
}
}
}
輸出打印如下:
1 get lock in read
3 get lock in read
2 get lock in read
0 get lock in read
4 get lock in read
2 finished read
4 finished read
3 finished read
0 finished read
1 finished read
0 get lock in write
0 finished write
1 get lock in write
1 finished write
2 get lock in write
2 finished write
5. CountDownLatch
主要用於多任務之間的同步,例如爲了完成某個任務,需要做n個動作,那麼這n個動作可以放到n個線程中,我們通過CountDownLatch等待n個動作完成。
public class CountDownLatchTest {
private static final CountDownLatch end = new CountDownLatch(5);
public void doTest() {
ExecutorService exec = Executors.newFixedThreadPool(5);
for(int i = 0; i < 5; i++) {
exec.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" do job");
Thread.sleep((long)(Math.random()*10000));
end.countDown();
System.out.println(Thread.currentThread().getName()+" finish job");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
try {
end.await();
System.out.println("all job has been finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
輸出打印
pool-1-thread-1 do job
pool-1-thread-2 do job
pool-1-thread-3 do job
pool-1-thread-4 do job
pool-1-thread-5 do job
pool-1-thread-1 finish job
pool-1-thread-2 finish job
pool-1-thread-5 finish job
pool-1-thread-4 finish job
pool-1-thread-3 finish job
all job has been finished
6. 循環柵欄 CyclicBarrier
同CountDownLatch類似,可以將任務分解爲n個步驟執行,但是它還提供新的功能:
*CyclicBarrier可以設置回調,在步驟執行完畢的時候自動調用該回調
*可以循環操作,也就是一次觸發完畢,計數器在執行完畢會自動清零,可以進入第二次觸發。
public class CyclicBarrierTest {
public void doTest() {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" all Job finished");
}
});
ExecutorService exec = Executors.newFixedThreadPool(5);
for(int i = 0; i < 5; i++) {
exec.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" do job");
Thread.sleep((long)(Math.random()*10000));
System.out.println(Thread.currentThread().getName()+" finish job");
cyclicBarrier.await();
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
});
}
}
}
用例輸出:
pool-1-thread-1 do job
pool-1-thread-3 do job
pool-1-thread-2 do job
pool-1-thread-4 do job
pool-1-thread-5 do job
pool-1-thread-4 finish job
pool-1-thread-2 finish job
pool-1-thread-5 finish job
pool-1-thread-3 finish job
pool-1-thread-1 finish job
pool-1-thread-1 all Job finished
這個例子是將任務拆分成5個步驟多線程執行,可以看到回調的調用是在最後一個步驟的線程裏面執行的。
7, LockSupport 線程阻塞工具類,可以用來代替sleep?https://agapple.iteye.com/blog/970055