第七章 Customizing Concurrency Classes(自定义并发类)【下】

来源:互联网 发布:java单例模式面试题 编辑:程序博客网 时间:2024/06/11 19:52
本章涉及内容:
  • 自定义ThreadPoolExecutor类
  • 实现基于优先级Executor类
  • 实现ThreadFactory接口生成自定义线程
  • 在Executor对象中使用自定义ThreadFactory
  • 在计划线程池运行自定义任务
  • 通过实现ThreadFactory接口为Fork/Join框架生成自定义线程
  • 在Fork/Join框架运行自定义任务
  • 实现自定义锁类
  • 基于优先级实现传输队列
  • 实现自己的原子对象

1、在Fork/Join框架运行自定义任务

Fork/Join内部存在两种元素;

  • 1、一个等待执行的队列任务
  • 2、执行队列任务的线程

当然你可以向Fork/Join投入Runnable和Callable接口实现的对象,只是不能利用work-stealing 算法带来的优势。

Fork/Join框架默认两种任务

  • 1、RecursiveAction : 任务不会返回值
  • 2、RecursiveTask : 任务的将会有返回值。

例子:继承ForkJoinTask任务将会打印执行日志

package com.jack;import java.util.Date;import java.util.concurrent.ForkJoinTask;public abstract class MyWorkerTask extends ForkJoinTask<Void> {/** *  */private static final long serialVersionUID = 1L;private String name;public MyWorkerTask(String name) {super();this.name = name;}@Overridepublic Void getRawResult() {return null;}@Overrideprotected void setRawResult(Void value) {}@Overrideprotected boolean exec() {Date startDate = new Date();compute();Date finishDate = new Date();long diff= finishDate.getTime() - startDate.getTime();System.out.printf("MyWorkerTask: %s : 花费 %d 秒完成了\n", name, diff);return true;}public String getName() {return name;}protected abstract void compute() ;}


总结:重写了exec的方法,增加日志
package com.jack;public class Task extends MyWorkerTask {/** *  */private static final long serialVersionUID = 1L;private int array[];private int start;private int end;public Task(String name, int array[], int start, int end) {super(name);this.array =array;this.start = start;this.end = end;}@Overrideprotected void compute() {if(end-start>100){int mid = (end+start)/2;Task task1 = new Task(this.getName()+"1", array, start, mid);Task task2 = new Task(this.getName()+"2", array, mid, end);invokeAll(task1, task2);} else {for (int i=start; i<end; i++){array[i] ++;}try{Thread.sleep(50);}catch(InterruptedException e){e.printStackTrace();}}}}

总结:自定义的ForkJoinTask类,同时实现compute的方法

package com.jack;import java.util.concurrent.ForkJoinPool;public class Main {public static void main(String[] args) throws Exception{int array[] = new int[10000];ForkJoinPool pool = new ForkJoinPool();Task task = new Task("task", array, 0, array.length);pool.invoke(task);pool.shutdown();System.out.printf("Main: Main方法结束了");}}
总结:

  • 1、创建长度为10000的数组作为一个任务。
  • 2、创建执行任务的ForkJoinPool线程池
  • 3、执行任务,关闭线程池。

日志:



扩展:

  • 1、setRawResult(): 这个方法是组装任务的结果,如果没有结果就制空
  • 2、getRawResult(): 这个方法是返回组装的结果,如果没有就返回null
  • 3、exec(): 这个方法实现逻辑的任务,具体的任务可以分配给compute()执行。

2、实现一个自定义锁

lock是java API提供最简单并发处理机制

  • lock() : 只要一个线程执行到这里就会锁定这段代码,直到这个线程执行完毕,其他线程才可以执行。
  • unlock(): 这个就是解除这个代码的锁定。

默认值实现Lock 的lock类ReentrantLock类

例子:将会实现自己的lock的类

package com.jack;import java.util.concurrent.TimeUnit;public class Task implements Runnable {private MyLock lock;private String name;public Task(MyLock lock, String name) {super();this.lock = lock;this.name = name;}@Overridepublic void run() {lock.lock();System.out.printf("任务: %s: 获取这个锁\n", name);try{TimeUnit.SECONDS.sleep(2);System.out.printf("任务: %s:释放这个锁\n", name);} catch (InterruptedException e){e.printStackTrace();} finally{lock.unlock();}}}


package com.jack;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.AbstractQueuedSynchronizer;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;public class MyLock implements Lock {private AbstractQueuedSynchronizer sync;public MyLock() {super();sync= new MyAbstractQueuedSynchronizer();}@Overridepublic void lock() {sync.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {try{return sync.tryAcquireNanos(1, 1000);} catch (InterruptedException e){e.printStackTrace();return false;}}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1, TimeUnit.NANOSECONDS.convert(time, unit));}@Overridepublic void unlock() {sync.release(1);}@Overridepublic Condition newCondition() {return  sync.new ConditionObject();}}

package com.jack;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class MyAbstractQueuedSynchronizer  extends AbstractQueuedSynchronizer{/** *  */private static final long serialVersionUID = 1L;private AtomicInteger  state;public MyAbstractQueuedSynchronizer() {super();this.state = new AtomicInteger(0);}@Overrideprotected boolean tryAcquire(int arg) {return state.compareAndSet(0,1);}@Overrideprotected boolean tryRelease(int arg) {return state.compareAndSet(1, 0);}}

package com.jack;import java.util.concurrent.TimeUnit;public class Main {public static void main(String[] args) throws Exception{MyLock lock = new MyLock();for (int i=0; i<10; i++){Task task = new Task(lock, "任务一" + i);Thread thread = new Thread(task);thread.start();}boolean value;do{try{value = lock.tryLock(1, TimeUnit.SECONDS);if(!value){System.out.printf("Main: 尝试获取这个锁\n");}}catch (InterruptedException e){e.printStackTrace();value = false;}}while (!value);System.out.printf("Main: 获取到这个锁\n");lock.unlock();System.out.printf("Main: 执行完成了");}}
日志:

任务: 任务一0: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一0:释放这个锁任务: 任务一1: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一1:释放这个锁任务: 任务一2: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一2:释放这个锁任务: 任务一3: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一3:释放这个锁任务: 任务一4: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一4:释放这个锁任务: 任务一5: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一5:释放这个锁任务: 任务一6: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一6:释放这个锁任务: 任务一7: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一7:释放这个锁任务: 任务一8: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一8:释放这个锁任务: 任务一9: 获取这个锁Main: 尝试获取这个锁Main: 尝试获取这个锁任务: 任务一9:释放这个锁Main: 获取到这个锁Main: 执行完成了

总结:

  • 1、MyAbstractQueuedSynchronizer改变锁的状态(类似小区门口指示牌,当前是否有空位,如果出去一辆就有空位了,空位数据加1,反之减一)
  • 2、Mylock实现lock,锁定的状态为1,释放为0(也就是只要状态为0,表示这段代码可以被其他线程使用)

3、基于优先级实现传输队列

Java API提供几种数据结构去实现并发:如下介绍两种

LinkedTransferQueue: 链表式传输队列,它可以用于生产者/消费者模型。它遵循FIFO,如果一方没有将会阻塞。

PriorityBlockingQueue: 这个基于优先级传输队列,就是贵宾(不是贵宾犬大笑)优先。

例子;实现生产者和消费者模型

package com.jack;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.PriorityBlockingQueue;import java.util.concurrent.TimeUnit;import java.util.concurrent.TransferQueue;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.locks.ReentrantLock;public class MyPriorityTransferQueue<E> extends PriorityBlockingQueue<E>implements TransferQueue<E>{/** *  */private static final long serialVersionUID = 1L;private AtomicInteger counter;private LinkedBlockingQueue<E> transfered;private ReentrantLock lock;public MyPriorityTransferQueue() {super();this.counter = new AtomicInteger(0);this.transfered = new LinkedBlockingQueue<E>();this.lock = new ReentrantLock();}@Overridepublic boolean tryTransfer(E e) {lock.lock();boolean value;if(counter.get() ==0){value=false;} else {put(e);value=true;}lock.unlock();return value;}@Overridepublic void transfer(E e) throws InterruptedException {lock.lock();if(counter.get() !=0){put(e);lock.unlock();} else {transfered.add(e);lock.unlock();synchronized (e) {e.wait();}}}@Overridepublic boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException {lock.lock();if(counter.get()!=0){put(e);lock.unlock();return true;} else {transfered.add(e);long newTimeout = TimeUnit.MILLISECONDS.convert(timeout, unit);lock.unlock();e.wait(newTimeout);lock.lock();if(transfered.contains(e)){transfered.remove(e);lock.unlock();return false;} else {lock.unlock();return true;}}}@Overridepublic boolean hasWaitingConsumer() {return (counter.get()!=0);}@Overridepublic int getWaitingConsumerCount() {return counter.get();}@Overridepublic E take() throws InterruptedException {lock.lock();counter.incrementAndGet();E value = transfered.poll();if(value ==null){lock.unlock();value=super.take();lock.lock();} else {synchronized (value) {value.notify();}}counter.decrementAndGet();lock.unlock();return value;}}
package com.jack;public class Event implements Comparable<Event>{private String thread;private int priority;public Event(String thread, int priority) {super();this.thread = thread;this.priority = priority;}public String getThread() {return thread;}public int getPriority() {return priority;}@Overridepublic int compareTo(Event o) {if(this.priority>o.getPriority()){return -1;} else if(this.priority<o.getPriority()){return 1;}return 0;}}

package com.jack;public class Producer implements Runnable{private MyPriorityTransferQueue<Event> buffer;public Producer(MyPriorityTransferQueue<Event> buffer) {super();this.buffer = buffer;}@Overridepublic void run() {for (int i=0; i<100; i++){Event event = new Event(Thread.currentThread().getName(), i);buffer.put(event);System.out.printf("生产者:%s: 优先级:%d\n", event.getThread(), event.getPriority());}}}
package com.jack;public class Consumer implements Runnable{private MyPriorityTransferQueue<Event> buffer;public Consumer(MyPriorityTransferQueue<Event> buffer) {super();this.buffer = buffer;}@Overridepublic void run() {for(int i=0; i<1002; i++){try{Event value = buffer.take();System.out.printf("消费者:%s: 优先级:%d\n", value.getThread(), value.getPriority());}catch (InterruptedException e){e.printStackTrace();}}}}

package com.jack;import java.util.concurrent.TimeUnit;public class Main {public static void main(String[] args) throws Exception{MyPriorityTransferQueue<Event> buffer = new MyPriorityTransferQueue<Event>();Producer producer = new Producer(buffer);Thread producerThreads[] = new Thread[10];for (int i=0; i<producerThreads.length; i++){producerThreads[i] = new Thread(producer);producerThreads[i].start();}Consumer consumer  = new Consumer(buffer);Thread consumerThread = new Thread(consumer);consumerThread.start();System.out.printf("Main: Buffer: 消费数量:%d\n", buffer.getWaitingConsumerCount());Event myEvent = new Event("核心事务1", 0);buffer.transfer(myEvent);System.out.printf("Main: 事件已经传输了.\n");for (int i=0; i<producerThreads.length; i++){try {producerThreads[i].join();}catch (InterruptedException e){e.printStackTrace();}}TimeUnit.SECONDS.sleep(1);System.out.printf("Main: Buffer: 消费数量: %d\n", buffer.getWaitingConsumerCount());myEvent = new Event("核心事件 2", 0);buffer.transfer(myEvent);consumerThread.join();System.out.println("Main:执行完毕");}}

总结:

  • 1、继承了PriorityBlockingQueue类,实现了TransferQueue完成插入元素操作,这些方法都关联生产者消费者


4、实现你自己的原子对象

package com.jack;import java.util.concurrent.atomic.AtomicInteger;public class ParkingCounter extends AtomicInteger{/** *  */private static final long serialVersionUID = 1L;private int maxNumber;public ParkingCounter(int maxNumber){set(0);this.maxNumber = maxNumber;}public boolean carIn(){for(;;){int value = get();if(value==maxNumber){System.out.printf("ParingCounter: 停车场已满了\n");return false;} else {int newValue = value+1;boolean changed = compareAndSet(value,newValue);if(changed){System.out.printf("ParkingCounter: 一辆车已经进入了\n");return true;}}}}public boolean carOut(){for(;;){int value = get();if(value==0){System.out.printf("ParkingCounter: 停车场已经空了\n");return false;}else {int newValue = value-1;boolean changed = compareAndSet(value, newValue);if(changed){System.out.printf("ParkingCounter: 一辆车已经使出了\n");return true;}}}}}
package com.jack;public class Sensor1 implements Runnable{private ParkingCounter counter;public Sensor1(ParkingCounter counter) {super();this.counter = counter;}@Overridepublic void run() {counter.carIn();counter.carIn();counter.carIn();counter.carIn();counter.carIn();counter.carOut();counter.carOut();counter.carOut();counter.carOut();counter.carIn();counter.carIn();counter.carIn();}}

package com.jack;public class Sensor2  implements Runnable{private ParkingCounter counter;public Sensor2(ParkingCounter counter) {super();this.counter = counter;}@Overridepublic void run() {counter.carIn();counter.carOut();counter.carOut();counter.carOut();counter.carOut();counter.carIn();counter.carIn();counter.carIn();counter.carOut();}}

package com.jack;public class Main {public static void main(String[] args) throws Exception{ParkingCounter counter = new ParkingCounter(5);Sensor1 sensor1 = new Sensor1(counter);Sensor2 sensor2 = new Sensor2(counter);Thread thread1 = new Thread(sensor1);Thread thread2 = new Thread(sensor2);thread1.start();thread2.start();thread1.join();thread2.join();System.out.printf("Main: 停车场还剩多少车:%d\n", counter.get());System.out.println("Main:执行结束");}}

日志:

ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParingCounter: 停车场已满了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经使出了ParkingCounter: 停车场已经空了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经使出了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经进入了ParkingCounter: 一辆车已经使出了Main: 停车场还剩多少车:3Main:执行结束
第七章完。。。

参考《Java 7 Concurrency Cookbook》

原创粉丝点击