Day29-线程池

线程池

获取线程池

Executor线程池定级接口

ExecutorService线程池接口,可通过submit(Runnable task)提交任务代码

Executors工厂类:可以获得一个线程池

​ 1、newFixedThreadPool(int nThreads)获得固定数量线程池

​ 2、newCachedThreadPool()获取动态数量线程池

调度线程池

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 调度线程池
 * 	1、周期执行:可以重复执行多次
 * 	2、延迟执行:只执行一次
 */
public class TestScheduledThreadPool {
	private static int num = 0;
	public static void main(String[] args) {
		//1、创建调度线程池
		ScheduledExecutorService es = Executors.newScheduledThreadPool(1);
		/*
		//延迟执行
		
		//2、提交任务
		//延迟5秒后执行
		//参数:任务 延时时间 延时时间的单位
		es.schedule(new Runnable() {
			
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName()+"执行了...");
			}
		}, 5, TimeUnit.SECONDS);
		
		//3、关闭线程池
		es.shutdown();
		*/
		
		//周期执行(固定周期)
		//参数 任务 第一次是否延迟 延时时间 延时时间的单位
		es.scheduleAtFixedRate(new Runnable() {
			
			@Override
			public void run() {
				//判断时间 主动结束
				System.out.println(Thread.currentThread().getName()+"....."+new Date().toLocaleString()+"运行了"+num+"次");
				num++;
				if(num==5) {
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//运行20次结束
				if (num == 20) {
					es.shutdown();
				}
			}
		}, 0, 1, TimeUnit.SECONDS);
		
		/*
		//固定频率 每次按照一个频率执行
		es.scheduleWithFixedDelay(new Runnable() {
			
			@Override
			public void run() {
				//判断时间 主动结束
				System.out.println(Thread.currentThread().getName()+"....."+new Date().toLocaleString()+"运行了"+num+"次");
				num++;
				if(num==5) {
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//运行20次结束
				if (num == 20) {
					es.shutdown();
				}
			}
		}, 0, 1, TimeUnit.SECONDS);
		*/
	}
}

Callable

JDK5加入,与Runnable接口类似,实现之后代表一个线程任务

Call方法具有泛型返回值,可以声明异常

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Callble与Runnable接口
 * 区别:
 * 	1、Callable中的call方法有返回值,Callable中call方法有异常类的声明
 * 	2、Runnable中的run方法没有返回值,Runnable中的run方法没有异常类的声明
 */
public class TestCallable1 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//计算1~100数的和
		//1、创建一个接口对象 得到可运行的线程任务
		Callable<Integer> callable = new Callable<Integer>() {

			@Override
			public Integer call() throws Exception {
				System.out.println(Thread.currentThread().getName() + "->开始计算");
				int sum = 0;
				for (int i = 1; i <= 100; i++) {
					sum += i;
				}
				System.out.println(Thread.currentThread().getName() + "->计算完毕");
				return sum;
			}
			
		}; 
		
		//2、callable转换成可执行任务
		FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
		//3、创建线程
		Thread t = new Thread(futureTask);
		t.start();
		//4、处理结果
		//get() 阻塞方法,如有必要,等待运算完获取结果
		Integer result = futureTask.get();
		System.out.println("1~100的和是:"+result);
	}
}

Future接口

异步接收提交所返回的状态结果,当中包含了call方法的返回值

Call方法具有泛型返回值,可以声明异常

同步:【举例】去操场集合,先站队,人全了一起去操场

异步:【举例】去操场集合,不用站队,人最终全到达操场

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TestCallable2 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//利用线程池 计算1~100数的和
		//1、创建线程池
		ExecutorService es = Executors.newFixedThreadPool(1);
		
		//2、提交任务
		Future<Integer> future = es.submit(new Callable<Integer>() {

			@Override
			public Integer call() throws Exception {
				System.out.println(Thread.currentThread().getName() + "->开始计算");
				int sum = 0;
				for (int i = 1; i <= 100; i++) {
					sum += i;
				}
				System.out.println(Thread.currentThread().getName() + "->计算完毕");
				return sum;
			}
		});
		
		//3、得到结果
		Integer result = future.get();
		System.out.println("结果是:" + result);
		//4、关闭线程池
		es.shutdown();
	}
}

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 练习:使用两个线程,并发计算1~50、51~100的和,再进行汇总统计
 */
public class TestCallable3 {
	public static void main(String[] args) {
		//1、创建线程池
		ExecutorService es = null;
		try {
			es = Executors.newFixedThreadPool(2);
			
			//2、创建任务
			Future<Integer> future1 = es.submit(new Callable<Integer>() {

				@Override
				public Integer call() throws Exception {
					System.out.println(Thread.currentThread().getName() + "->开始计算");
					int sum = 0;
					for (int i = 0; i <= 50; i++) {
						sum += i;
					}
					System.out.println(Thread.currentThread().getName() + "->计算完毕");
					return sum;
				}

			});
			
			Future<Integer> future2 = es.submit(new Callable<Integer>() {

				@Override
				public Integer call() throws Exception {
					System.out.println(Thread.currentThread().getName() + "->开始计算");
					int sum = 0;
					for (int i = 51; i <= 100; i++) {
						sum += i;
					}
					System.out.println(Thread.currentThread().getName() + "->计算完毕");
					return sum;
				}

			});
			
			//3、计算结果
			Integer result = future1.get() + future2.get();
			System.out.println("结果是:"+result);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//4、关闭线程池 可以在finall里关闭
			es.shutdown();			
		}
		
	}
}

Lock锁

【面试题】Synchronized和Lock的区别

类别 synchronized lock
存在层次 java关键字,在jvm层面上 是一个类
锁释放 1、获取所得线程执行完同步代码,释放
2、线程执行发生异常,jvm会让线程释放锁易造成线程死锁
在finally中必须释放锁,不然容易造成线程死锁
锁的获取 假设A线程获得锁,B线程等待。
如果A线程阻塞,B线程会一直等待
Lock可以尝试获得锁,线程可以不用一-直等待
锁状态 无法判断 可以判断
锁类型 可重入、不可中断、非公平 可重入、可中断、可公平或非公平
性能 少量同步 大量同步

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TicketRunnable implements Runnable{

	private int tikNum = 5000;
	//创建锁对象 ReentrantLock可重复锁
	private Lock lock = new ReentrantLock();
	@Override
	public void run() {
		while (true) {
			//想把谁放在一块 加锁
			lock.lock();
			try {
				if (tikNum <= 0) {
					break;
				}
				System.out.println(Thread.currentThread().getName() + "卖了" + tikNum + "张");
				tikNum--;
			} finally {
				//释放锁
				lock.unlock();
			}
		}
	}
	
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestThread {
	public static void main(String[] args) throws Exception {
//		//创建任务
//		TicketRunnable tr = new TicketRunnable();
//		//创建四个窗口
//		Thread t1 = new Thread(tr,"1号");
//		Thread t2 = new Thread(tr,"2号");
//		Thread t3 = new Thread(tr,"3号");
//		Thread t4 = new Thread(tr,"4号");
//		//开启线程
//		t1.start();
//		t2.start();
//		t3.start();
//		t4.start();
//		//join
//		t1.join();
//		t2.join();
//		t3.join();
//		t4.join();
//		
//		System.out.println("程序结束");
		
		//创建任务
		TicketRunnable tr = new TicketRunnable();
		//创建线程池
		ExecutorService es = Executors.newFixedThreadPool(4);
		//提交任务
		for (int i = 0; i < 4; i++) {
			es.submit(tr);
		}
		//关闭线程池
		es.shutdown();
	}
}

重入锁

ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能

读写锁

ReentrantReadWriteLock:一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁

支持多次分配读锁,多个读操作可以并发执行

互斥规则:

写-写:互斥,阻塞

读-写:互斥,读阻塞写、写阻塞读

读-读:不互斥,不阻塞

在读操作远远大于写操作的环境中,可在保障线程安全的情况下,提高运行效率

import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class ReentrantReadWriteLock1 {
	private String value;
	//可重复锁
//	private ReentrantLock lock = new ReentrantLock();
	//读写锁
	private ReentrantReadWriteLock rrl = new ReentrantReadWriteLock();
	//获取读的锁
	private ReadLock readLock = rrl.readLock();
	//获取写的锁
	private WriteLock writeLock = rrl.writeLock();
	
	//读
	public String getValue() {
		//上锁
		//lock.lock();
		readLock.lock();
		try {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("我读到了"+this.value);
			return value;
		} finally {
			//释放锁
//			lock.unlock();
			readLock.unlock();
		}
	}
	
	//写
	public void setValue(String value) {
		//上锁
		//lock.lock();
		writeLock.lock();
		try {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("写入:"+value);
			this.value = value;
		} finally {
			//释放锁
			//lock.unlock();
			writeLock.unlock();
		}
	}
}

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestReentrantReadWriteLock1 {
	public static void main(String[] args) {
		//创建任务
		ReentrantReadWriteLock1 rrw = new ReentrantReadWriteLock1();
		
		//创建线程池
		ExecutorService es = Executors.newFixedThreadPool(20);
		//获取读的任务
		Runnable read = new Runnable() {
			
			@Override
			public void run() {
				rrw.getValue();
			}
		};
		//获取写的任务
		Runnable write = new Runnable() {
			
			@Override
			public void run() {
				rrw.setValue("tom"+new Random().nextInt(100));
			}
		};
		//提交任务
		//获取时间,开始毫秒值,结束毫秒值,它们的差值比较效率
		long start = System.currentTimeMillis();
		
		//2个写的任务
		for (int i = 0; i < 2; i++) {
			es.submit(write);
		}
		//18个读的任务
		for (int i = 0; i < 18; i++) {
			es.submit(read);
		}
		//关闭线程池
		es.shutdown();
		while (!es.isTerminated()) {
			
		}
		long end = System.currentTimeMillis();
		System.out.println("时间差:"+(end - start));
	}
}

线程安全的集合

CopyOnWriteArrayList

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Demo1 {
	public static void main(String[] args) {
		//1、创建集合对象
//		ArrayList<String> arrayList = new ArrayList<String>();
//		List<String> synList = Collections.synchronizedList(arrayList);
		CopyOnWriteArrayList<String> synList = new CopyOnWriteArrayList<String>();
		//2、创建线程添加元素
		for (int i = 0; i < 20; i++) {
			int temp = i;
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					for (int j = 0; j < 10; j++) {
						synList.add(Thread.currentThread().getName()+"-----"+temp);
						System.out.println(synList);
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		}
	}
}

CopyOnWriteArraySet

import java.util.Random;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo2 {
	public static void main(String[] args) {
		//创建集合对象
//		CopyOnWriteArrayList<String> set=new CopyOnWriteArrayList<String>();
		CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<String>();
		//创建线程池
		ExecutorService es = Executors.newFixedThreadPool(5);
		//提交任务
		for (int i = 0; i < 5; i++) {
			es.submit(new Runnable() {
				
				@Override
				public void run() {
					for (int j = 0; j < 30; j++) {
						set.add(Thread.currentThread().getName()+"-----"+new Random().nextInt(1000));

					}
				}
			});
		}
		//关闭线程池
		es.shutdown();
		while (!es.isTerminated()) {
			
		}
		System.out.println("集合中元素的个数:"+set.size());
		for (String string : set) {
			System.out.println(string);
		}
	}
}

import java.util.concurrent.CopyOnWriteArraySet;

public class Demo3 {
	public static void main(String[] args) {
		//创建集合对象
		CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<String>();
		//添加元素
		set.add("A");
		set.add("B");
		set.add("C");
		set.add("D");
		System.out.println("元素个数:"+set.size());
	}
}

ConcurrentHashMap【面试】

CAS无锁算法【面试】

比较交换算法(Compare And Swap) 乐观锁

修改的方法包括三个参数(V,E,N)

V:要更新的变量

E:预期值

N:新值

V == E,V=N;否则表示已经更新过,则取消当前操作

import java.util.concurrent.ConcurrentHashMap;

public class Demo4 {
	public static void main(String[] args) {
		//创建集合
		ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
		//创建线程
		for (int i = 0; i < 5; i++) {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					for (int j = 0; j < 10; j++) {
						map.put(Thread.currentThread().getName()+"---"+j, j+" ");
						System.out.println(map);
					}
				}
			}).start();
		}
				
	}
}

Queue

import java.util.LinkedList;
import java.util.Queue;

/**
 * 队列:先进先出
 * Queue(接口)
 */
public class Demo5 {
	public static void main(String[] args) {
		//队列 先进先出 (FIFO)
		Queue<String> queue = new LinkedList<String>();
		//入队
		queue.offer("A");
		queue.offer("B");
		queue.offer("C");
		queue.offer("D");
		queue.offer("E");
		System.out.println("入队完毕"+queue.size());
		
		//出队
		int count = queue.size();
		for (int i = 0; i < count; i++) {
			//poll获取第一个元素移除 peek获取第一个元素不移除
			System.out.println(queue.poll());
//			System.out.println(queue.peek());
		}
		System.out.println("出队完毕"+queue.size());
	}
}

import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * ConcurrentLinkedQueue
 */
public class Demo6 {
	public static void main(String[] args) throws Exception {
		//创建集合对象
		ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
		//入队
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 1; i <= 5; i++) {
					queue.offer(i);
				}
			}
		});
		
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 6; i <= 10; i++) {
					queue.offer(i);
				}
			}
		});
		//启动线程
		t1.start();
		t2.start();
		//阻塞
		t1.join();
		t2.join();
		System.out.println("出队:");
		int count = queue.size();
		for (int i = 0; i < count; i++) {
			System.out.println(queue.poll());
		}
	}
}

BlockingQueue

ArrayBlockingQueue

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * BlockingQueue阻塞队列
 * ArrayBlockingQueue数组支持的
 */
public class Demo7 {
	public static void main(String[] args) throws InterruptedException {
		//创建一个有界集合
		BlockingQueue<String> queue = new ArrayBlockingQueue<String>(5);
		//入队
		queue.put("A");
		queue.put("B");
		queue.put("C");
		queue.put("D");
		queue.put("E");
		System.out.println("元素个数:"+queue.size());
//		queue.put("F");满了就等待
		queue.take();
		queue.put("F");
		System.out.println("元素个数:"+queue.size());
		int count = queue.size();
		for (int i = 0; i < count; i++) {
			System.out.println(queue.take());
		}
	}
}

LinkedBlockingQueue

队列完成生产者消费者模式

/**
 * 队列完成生产者消费者模式
 * 利用put和take方法
 * void put(E e) //将指定元素插入此队列中,如果没有可用空间,则等待。
    E take() //获取并移除此队列头部元素,如果没有可用元素,则等待。
 */

import java.util.concurrent.ArrayBlockingQueue;

public class Demo8 {
	public static void main(String[] args) {
		
		//创建一个有界队列
		ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(5);
		//创建2个线程
		//生产线程
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 1; i <= 30; i++) {
					try {
						queue.put(i);
						System.out.println(Thread.currentThread().getName()+"生产了第"+i+"个蛋糕");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		//消费线程
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 1; i <= 30; i++) {
					try {
						Integer n = queue.take();
						System.out.println(Thread.currentThread().getName()+"消费了第"+n+"个蛋糕");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		//启动线程
		t1.start();
		t2.start();
		
	}

}

多线程的三个特性【面试】

原子性(互斥性)

可见性

有序性

posted @ 2021-08-09 21:21  CN_Darren  阅读(49)  评论(0)    收藏  举报