【Java高并发学习】读写锁、倒计时器、LockSupport、线程池

来源:互联网 发布:星际争霸1汉化软件 编辑:程序博客网 时间:2024/06/05 08:21


1.ReadWriteLock读写锁

JDK5中提供了读写锁,可以有效地减少锁竞争提高性能。比如线程A1、A2、A3进行写操作,B1、B2、B3进行读操作,在使用重入锁、内部锁(synchronized)时,理论上所有的读之间、写之间、读写之间都是串行的。当B1在进行读操作时,B2、B3也得等待B1的锁资源释放,但是读操作并不会破坏数据的完整性,这种等待便没有了意义。

 读写读非阻塞阻塞写阻塞阻塞

import java.util.Random;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 读写锁测试 * @author wsz * @date 2017年12月5日 */public class ReadWriteLockDemo {//重入锁private static Lock lock = new ReentrantLock();//读写锁private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();private static Lock readLock = readWriteLock.readLock();private static Lock writeLock = readWriteLock.writeLock();//测试变量private int value;//读操作public Object handleRead(Lock lock) throws InterruptedException {try {lock.lock();Thread.sleep(1000);//模拟耗时return value;}finally {lock.unlock();}}//写操作public void handleWrite(Lock lock,int index) throws InterruptedException {try {lock.lock();Thread.sleep(1000);//模拟耗时this.value = index;}finally {lock.unlock();}}public static void main(String[] args) {final ReadWriteLockDemo demo = new ReadWriteLockDemo();Runnable read = new Runnable() {@Overridepublic void run() {try {System.out.println(demo.handleRead(readLock));//System.out.println(demo.handleRead(lock)); 重入锁} catch (InterruptedException e) {e.printStackTrace();}}};Runnable write = new Runnable() {@Overridepublic void run() {try {demo.handleWrite(writeLock, new Random().nextInt());//demo.handleWrite(lock, new Random().nextInt()); 重入锁} catch (InterruptedException e) {e.printStackTrace();}}};for(int i = 0; i< 20; i++) {new Thread(read).start();//读线程并行}for(int i = 0; i< 5; i++) {new Thread(write).start();//写线程串行}}}

2.倒计时器:CountDownLatch

可以让某一个线程等待直到倒计时结束,再开始执行。
import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 倒计时器 * @author wsz * @date 2017年12月5日 */public class CountDownLatchDemo implements Runnable{static final CountDownLatch cdl = new CountDownLatch(10);//参数为计数个数static final CountDownLatchDemo demo = new CountDownLatchDemo();@Overridepublic void run() {try {Thread.sleep(new Random().nextInt(10)*1000);System.out.println("ok");cdl.countDown();//完成一个线程,计数-1} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) throws InterruptedException {ExecutorService pool = Executors.newFixedThreadPool(10);for(int i = 0; i< 15;i ++) {//线程池数量<10,将一直等待;//线程池数量>=10 将按时打印all over,超过的次数将继续打印okpool.submit(demo);}cdl.await();//主线程在CountDownLatch上等待,10次均已完成后,主线程才能继续执行System.out.println("all over");cdl.countDown();}}

3.线程阻塞工具类:LockSupport

  1. 在线程内任意位置让线程阻塞
  2. 相比Thread.suspend(),弥补了由于resume()在前发生,导致线程无法继续执行的情况
  3. 相比Object.wait(),不需要先获得某个对象的锁,也不会抛出InterruptedException异常
  4. LockSupport.unpark(Runnable target)可以阻塞线程,此外还提供了限时的等待方法
  5. 使用类似信号量的机制,为每一个线程准备一个许可,如果许可可用,park()函数会立即返回,并消费这个许可,如果不可用,就会阻塞。unpark()则使一个许可变为可用(许可不可累加)。
  6. 处于park()挂起状态的线程为WAITING
import java.util.concurrent.locks.LockSupport;/** * LockSupport案例 * 依然无法保证unpark()方法发生在park()方法之后。 * LockSupport使用类似信号量的机制。它为每一个线程提供一个许可, * 如果许可可用,park()函数会立即返回,并消费这个许可(将许可变为不可用) * 如果许可不可用,就会阻塞,unpark()使得一个许可变为可用(但不可累加) * @author wsz * @date 2017年12月5日 */public class LockSupportDemo {public static Object u = new Object();static ChangeObjectThread t1  = new ChangeObjectThread("t1");static ChangeObjectThread t2  = new ChangeObjectThread("t2");public static class ChangeObjectThread extends Thread{public ChangeObjectThread(String name) {super.setName(name);}@Overridepublic void run() {synchronized(u) {System.out.println("in "+getName());LockSupport.park();}}}public static void main(String[] args) throws InterruptedException {t1.start();Thread.sleep(1000);t2.start();LockSupport.unpark(t1);//进行阻塞,状态变为WAITINGLockSupport.unpark(t2);//进行阻塞,状态变为WAITINGt1.join();t2.join();}}

4.线程池



import java.util.Random;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** * 定时任务 * 如果任务程序本身抛出异常,后续所有执行都将被中断 * @author wsz * @date 2017年12月5日 */public class ScheduledExecutorServiceDemo {public static void main(String[] args) {ScheduledExecutorService ses = Executors.newScheduledThreadPool(10);/** * scheduleAtFixedRate保证之前的任务已完成 * 当操作时间>调度周期2s时,后一个任务会立即执行 */ses.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);//模拟操作执行1sSystem.out.println(new Random().nextInt());} catch (InterruptedException e) {e.printStackTrace();}}}, 3, 2, TimeUnit.SECONDS);//3初始延迟,每2秒执行一次}}




原创粉丝点击