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