package com.kuang.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
// 使用普通的ArrayList并发时会出现以下异常
//java.util.ConcurrentModificationException并发修改异常
public class ListTest {
public static void main(String[] args) {
//List list=new ArrayList<>();
// 解决方案
// 一:List list=new Vector<>();
// 二:List list= Collections.synchronizedList(new ArrayList<>());
// 三:List list=new CopyOnWriteArrayList<>();
// CopyOnWrite 写入时复制
// 在写入的时候避免覆盖,出现数据问题
List list=new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
多个线程调用的时候,读取时是固定的,写入时可能会发生覆盖,所以计算机程序设计领域优化的策略是使用CopyOnWriteArrayList
package com.kuang.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
// 同理可证
// java.util.ConcurrentModificationException
public class SetTest {
public static void main(String[] args) {
//Set set=new HashSet<>();
//Set set= Collections.synchronizedSet(new HashSet<>());
Set set=new CopyOnWriteArraySet<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
HashSet底层是HashMap
public HashSet() {
map = new HashMap<>();
}
// map中key不可重复的
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();//不变的值
package com.kuang.unsafe;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
//java.util.ConcurrentModificationException
public class MapTest {
public static void main(String[] args) {
//HashMap map = new HashMap<>();
Map map = new ConcurrentHashMap<>();
for (int i = 1; i <= 20; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,3));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
Runnable和Callable实现类有:FutureTask
细节:有缓存、结果可能需要等待,会阻塞
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("run()");
}
}.start();
new Thread(new FutureTask()).start();
new Thread(new FutureTask(Callable)).start();
package com.kuang.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest {
public static void main(String[] args) {
/*new Thread(new Runnable() {
@Override
public void run() {
}
}).start();*/
MyThread thread=new MyThread();
FutureTask task = new FutureTask<>(thread);//适配类
new Thread(task,"A").start();
new Thread(task,"B").start();
try {
// get()方法可能会产生阻塞,把它放到最后
Integer res = task.get();
// 使用异步通信来处理
System.out.println(res);//123
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable{
@Override
public Integer call() throws Exception {
System.out.println("call()");//会打印1个
// 耗时操作
return 123;
}
}
减法计数器CountDownLatch:指定线程执行完毕再执行操作
package com.kuang.add;
import java.util.concurrent.CountDownLatch;
// 计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
// 6个人要出去才能关门
// 要执行的任务再使用
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"go out");
countDownLatch.countDown();//-1
},String.valueOf(i)).start();
}
countDownLatch.await();// 等待计数器归0,再向下执行
System.out.println("close door");
}
}
原理:每次线程调用countDown()方法计数器就减1,当减到0时,await()方法就会被唤醒,继续向下执行
加法计数器CyclicBarrier :执行达到指定线程数再执行操作 Lambda表达式无法访问外部变量i
package com.kuang.add;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
// 集齐七龙珠召唤神龙
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("召唤神龙成功");
});
for (int i = 1; i <= 7; i++) {
final int temp=i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"集齐第"+temp+"个龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
信号量Semaphore:多个共享资源互斥使用(并发限流,控制最大线程数)
package com.kuang.add;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
// 线程数量:停车位 3
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "获得车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
原理:semaphore.acquire();获得,假设已经满了等待,等待被释放为止
semaphore.release();释放,将当前信号量释放+1,唤醒等待的线程
package com.kuang.rw;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 独占锁(写锁):一次只被一个线程占有
* 共享锁(读锁):多个线程可以同时占有
* 读-读 可以共存
* 写-写 不能共存
* 读-写 不能共存
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCacheLock cacheLock = new MyCacheLock();
// 写入操作
for (int i = 1; i <=5; i++) {
final int temp=i;
new Thread(()->{
cacheLock.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
// 读取操作
for (int i = 1; i <=5; i++) {
final int temp=i;
new Thread(()->{
cacheLock.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class MyCacheLock{
private volatile Map map=new HashMap<>();
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
public void put(String key,Object value){
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
}catch (Exception e){
e.printStackTrace();
}finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String key){
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
}catch (Exception e){
e.printStackTrace();
}finally {
readWriteLock.readLock().unlock();
}
}
}
/**
* 抛出异常
*/
public static void test1(){
ArrayBlockingQueue
/**
* 有返回值,不抛出异常
*/
public static void test2(){
ArrayBlockingQueue
/**
* 等待,一直阻塞
*/
public static void test3() throws InterruptedException {
ArrayBlockingQueue
/**
* 超时等待,过时就不等
*/
public static void test4() throws InterruptedException {
ArrayBlockingQueue
方式 | 抛出异常 | 有返回值,不抛异常 | 等待 | 超时等待 |
添加 | add() | offer() | put() | offer(,,) |
移除 | remove() | poll() | take() | poll(,) |
检测队首元素 | element() | peek() | - | - |
package com.kuang.bq;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
* 同步队列
* 和其他阻塞队列不一致,SynchronousQueue不存储元素
* put了一个元素,必须从里面take取出来,否则不能再put进去值
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue blockingQueue = new SynchronousQueue<>();//同步队列
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+" put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName()+" put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName()+" put 3");
blockingQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T1").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" get "+blockingQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" get "+blockingQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" get "+blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T2").start();
}
}
程序的运行本质上是占用系统的资源,优化资源的使用
线程池、连接池、对象池、内存池....
池化技术:事先准备好一些资源,需要使用时直接来我这拿即可,用完之后还给我就行
线程池的好处
降低资源的消耗、提高响应的速度、方便管理
线程复用、控制最大并发数、管理线程
三个方法
package com.kuang.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo01 {
public static void main(String[] args) {
//ExecutorService service = Executors.newSingleThreadExecutor();//单线程
//ExecutorService service = Executors.newFixedThreadPool(5);//固定线程池大小
ExecutorService service = Executors.newCachedThreadPool();//可大可小
try{
for (int i = 0; i < 10; i++) {
// 使用了线程池之后,使用线程池创建线程
service.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭线程
service.shutdown();
}
}
}
自定义线程池7个参数(推荐)+四大拒绝策略
package com.kuang.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo02 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,//核心线程数量
5,//最大线程数量
3,//等待时间
TimeUnit.SECONDS,//时间单位
new LinkedBlockingQueue<>(3),//阻塞队列
Executors.defaultThreadFactory(),//线程工厂
//new ThreadPoolExecutor.AbortPolicy() //队列满了抛异常java.util.concurrent.RejectedExecutionException
new ThreadPoolExecutor.CallerRunsPolicy() //哪里来就从哪里去
//new ThreadPoolExecutor.DiscardPolicy() // 队列满了,丢掉任务,不会抛异常
//new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试和最早的开始竞争,不会抛异常
);
try{
for (int i = 1; i <= 9; i++) {
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPoolExecutor.shutdown();
}
}
}
System.out.println(Runtime.getRuntime().availableProcessors());//获取CPU核数
最大线程数如何设置
CPU密集型:几核就定义几,可以保持CPU效率高
IO密集型:大于判断非常耗IO的线程 通常设置其2倍(程序 15个大型任务 io非常占用资源,这里我们设置其2倍即30)
函数型接口 有一个输入参数,有一个输出
package com.kuang.function;
import java.util.function.Function;
// 函数型接口 泛型有一个输入参数,有一个输出
// 只要是函数型接口,都可以用Lambda表达式简化
public class Demo01 {
public static void main(String[] args) {
/*Function function=new Function() {
@Override
public String apply(String str) {
return str;
}
};*/
Function function=(str)->{return str;};
System.out.println(function.apply("abc"));
}
}
断定型接口 有一个输入参数 只能返回布尔值
package com.kuang.function;
import java.util.function.Predicate;
// 断定型接口 泛型有一个输入参数 只能返回布尔值
public class Demo02 {
public static void main(String[] args) {
// 判断字符串是否为空
/*Predicate predicate=new Predicate() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};*/
Predicate predicate=str->str.isEmpty();
System.out.println(predicate.test(""));
}
}
消费型接口 只有一个输入参数 没有返回值
package com.kuang.function;
import java.util.function.Consumer;
// 消费型接口 泛型只有一个输入参数 没有返回值
public class Demo03 {
public static void main(String[] args) {
// 打印字符串
/*Consumer consumer=new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
};*/
Consumer consumer=s -> System.out.println(s);
consumer.accept("abc");
}
}
供给型接口 只返回不输入
package com.kuang.function;
import java.util.function.Supplier;
// 供给型接口:没有参数,只有返回值
public class Demo04 {
public static void main(String[] args) {
/*Supplier supplier=new Supplier() {
@Override
public Integer get() {
System.out.println("get()");
return 1024;
}
};*/
Supplier supplier=()->{
System.out.println("get()");
return 1024;
};
System.out.println(supplier.get());
}
}
package com.kuang.stream;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
User u1 = new User(1, "a", 21);
User u2 = new User(2, "b", 22);
User u3 = new User(3, "c", 23);
User u4 = new User(4, "d", 24);
User u5 = new User(5, "e", 25);
User u6 = new User(6, "f", 26);
// 集合就是存储
List list = Arrays.asList(u1, u2, u3, u4, u5, u6);
// 计算交给Stream流
// 链式编程
list.stream().filter(u->u.getId()%2==0)
.filter(u->u.getAge()>23)
.map(u->u.getName().toUpperCase())
.sorted(((o1, o2) -> o2.compareTo(o1)))
.limit(1)
.forEach(System.out::println);
}
}