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

浙公网安备 33010602011771号