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

本文介绍了如何定制Fork/Join任务以实现任务执行的日志记录,并展示了如何实现自定义锁类、基于优先级的传输队列及自定义原子对象等高级并发控制机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章涉及内容:
  • 自定义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;
	}

	@Override
	public Void getRawResult() {
		return null;
	}

	@Override
	protected void setRawResult(Void value) {
		
	}

	@Override
	protected 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;
	}

	@Override
	protected 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;
	}


	@Override
	public 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();
	}

	@Override
	public void lock() {
		sync.acquire(1);
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
		
	}

	@Override
	public boolean tryLock() {
		try{
			return sync.tryAcquireNanos(1, 1000);
		} catch (InterruptedException e){
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		
		return sync.tryAcquireNanos(1, TimeUnit.NANOSECONDS.convert(time, unit));
	}

	@Override
	public void unlock() {
		sync.release(1);
		
	}

	@Override
	public 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);
	}
	@Override
	protected boolean tryAcquire(int arg) {
		
		return state.compareAndSet(0,1);
	}
	@Override
	protected 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();
	}

	@Override
	public boolean tryTransfer(E e) {
		lock.lock();
		boolean value;
		if(counter.get() ==0){
			value=false;
		} else {
			put(e);
			value=true;
		}
		lock.unlock();
		return value;
	}

	@Override
	public 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();
			}
		}
		
	}

	@Override
	public 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;
			}
		}
	}

	@Override
	public boolean hasWaitingConsumer() {
		
		return (counter.get()!=0);
	}

	@Override
	public int getWaitingConsumerCount() {
		return counter.get();
	}

	@Override
	public 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;
	}


	@Override
	public 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;
	}



	@Override
	public 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;
	}


	@Override
	public 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;
	}

	@Override
	public 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;
	}

	

	@Override
	public 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: 停车场还剩多少车:3
Main:执行结束
第七章完。。。

参考《Java 7 Concurrency Cookbook》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值