java.util.concurrent 并发工具包(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qinshi965273101/article/details/82785114

一、ThreadPoolExecutor 线程池执行者

  • 初始化线程池的参数
corePoolSize 核心线程大小
maximumPoolSize 最大线程大小
keepAliveTime 空余的多余线程保持时间
unit 时间单位
workQueue 阻塞队列
handler 拒绝服务助手
  • 线程池内部运行机制

1、当有任务委托给线程池,若池中线程数量 < 核心线程数量,则创建新的线程,即使有空闲线程。

2、若核心线程数量已满,且没有空闲,则把任务放入阻塞队列

3、若核心线程阻塞队列都没有空闲,此时再来任务,则判断当前池内线程数量是否 < 最大线程数量。若小于则创建临时线程去处理该任务。

4、若核心线程阻塞队列临时线程都已经到达上限,且被占用。此时再来任务,则由拒绝助手去处理。

  • 代码示例
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorDemo {

	public static void main(String[] args) throws InterruptedException {
		
		//阻塞队列
		ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(2);
		//拒绝助手
		RejectedExecutionHandler handler = new RejectedExecutionHandler() {
			@Override
			public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
				System.out.println("线程池已满  ##### 任务被拒绝 ");
			}
		};
		//创建线程池
		ThreadPoolExecutor  pool =  new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, workQueue, handler);
										
		//1,2被核心线程处理
		pool.execute(new RunnableDemo(1,5000L));
		pool.execute(new RunnableDemo(2,5000L));
		Thread.sleep(100);
		//3,4放入阻塞队列,等核心线程或临时线程有空闲了再处理
		pool.execute(new RunnableDemo(3,2000L));
		pool.execute(new RunnableDemo(4,2000L));
		Thread.sleep(100);
		//5,6被临时线程处理
		pool.execute(new RunnableDemo(5,2000L));
		pool.execute(new RunnableDemo(6,2000L));
		Thread.sleep(100);
		//7,8被拒接助手处理了
		pool.execute(new RunnableDemo(7,2000L));
		pool.execute(new RunnableDemo(8,2000L));
		
		//线程池关闭
		pool.shutdown();
		
	}

}

class RunnableDemo implements Runnable {
	
	private int id;
	private long time;
	
	public RunnableDemo(int id, long time) {
		this.id = id;
		this.time = time;
	}
	
	@Override
	public void run() {
		try {
			
			System.out.println("id=" + id + " 开始执行!时间:" + System.currentTimeMillis());
			Thread.sleep(time);
			System.out.println("id=" + id + " 执行完成!时间:" + System.currentTimeMillis());
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
}

二、ExecutorService 执行器服务

  • 获取线程池

通过Executors类的各个静态方法,可以直接获取常用配置的线程池。

例如:

ExecutorService executorService = Executors.newFixedThreadPool(5);

其实内部也是用ThreadPoolExecutor来实现:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • 执行
execute(Runnable) 没有返回结果
submit(Runnable) 返回值类型为 Future,可以通过Future的get()方法来观察任务是否执行结束。若没结束,则该方法会阻塞。
submit(Callable)

与submit(Runnable)类似,唯一区别是submit(Callable)

还可以通过get() 方法获取返回结果。

invokeAny() 入参为一个Callable或其子接口实例对象的集合,如果其中一个任务执行完成或者异常,其他的Callable将被取消。并返回其中一个Callable的执行结果。
invokeAll() 入参为一个Callable或其子接口实例对象的集合,执行所有任务,并返回一个Future对象的集合。但是无法通过Future知道任务是正常结束还是执行异常。
  • 关闭线程池
shutdown() 执行后则不再接受任务,直到任务执行完成才关闭
shutdownNow() 立即关闭
  • 代码示例
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorServiceDemo {
	
	public static void main(String[] args) throws Exception {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		Future<String> future = executorService.submit(new CallableDemo());
		
		//阻塞直到任务结束
		System.out.println(future.get());
		
		executorService.shutdown();
		
	}
}

class CallableDemo implements Callable<String> {

	public String call() throws Exception {
		System.out.println("开始执行!");
		Thread.sleep(3000);
		System.out.println("执行结束!");
		
		return "china@!";
	}
	
}

三、Lock锁

作用类似synchronized,但是更灵活,通过lock(),unlock()两个方法配合使用,保证线程安全。

lock() 将 Lock 实例锁定
lockInterruptibly() lockInterruptibly() 方法将会被调用线程锁定,除非该线程被打断。此外,如果一个线程在通过这个方法来锁定 Lock 对象时进入阻塞等待,而它被打断了的话,该线程将会退出这个方法调用。
tryLock() 试图立即锁定 Lock 实例。并返回成功结果,永不阻塞
unlock 对 Lock 实例解锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {
	public static void main(String[] args) throws InterruptedException {
		Lock lock = new ReentrantLock();
		
		Thread t1 = new Thread(new T1(lock));
		Thread t3 = new Thread(new T1(lock));
			t1.start();
			Thread.sleep(100);
			t3.start();
			t3.interrupt();
		
	}
}

class T1 implements Runnable {
	
	Lock lock = null;
	
	public T1(Lock lock) {
		this.lock = lock;
	}
	public void run() {
		
		try {
			//当当前执行线程被打断时,当前线程会退出这个方法调用
			lock.lockInterruptibly();
			System.out.println("任务开始执行!");
			Thread.sleep(2000);
			System.out.println("任务执行结束!");
			
		} catch (Exception e) {
			System.out.println("线程被打断");
		}finally {
			lock.unlock();
		}
		
	}
	
}

四、ReadWriteLock读写锁

读是可以并发处理的,但是读和写,或者多个写是不可以并发处理的。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
	
	public static String name = "lisi";
	public static void main(String[] args) {
		ReadWriteLock lock = new ReentrantReadWriteLock();
		//read可以并发
		new Thread(new TRead(lock)).start();
		new Thread(new TRead(lock)).start();
		new Thread(new TRead(lock)).start();
		//read+write 或者 多个write不能并发
		new Thread(new TWrite(lock)).start();
		new Thread(new TWrite(lock)).start();
		new Thread(new TRead(lock)).start();
		
	}
}

class TWrite implements Runnable {
	private ReadWriteLock lock = null;
	
	public TWrite(ReadWriteLock lock) {
		this.lock = lock;
	}
	
	public void run() {
		
		try {
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getId() + "  # 开始写数据");
			Thread.sleep(2000);
			ReadWriteLockDemo.name ="wangwu";
			System.out.println(Thread.currentThread().getId() + "  # 数据写入成功" + ReadWriteLockDemo.name);
			lock.writeLock().unlock();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
}

class TRead implements Runnable {
	private ReadWriteLock lock = null;
	
	public TRead(ReadWriteLock lock) {
		this.lock = lock;
	}
	
	public void run() {
		
		try {
			lock.readLock().lock();
			System.out.println(Thread.currentThread().getId() + "  # 开始读数据");
			Thread.sleep(2000);
			ReadWriteLockDemo.name ="wangwu";
			System.out.println(Thread.currentThread().getId() + "  # 读取到数据" + ReadWriteLockDemo.name);
			lock.readLock().unlock();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
}

猜你喜欢

转载自blog.csdn.net/qinshi965273101/article/details/82785114