JUC
NotSafeDemo
list 不安全
List<String> list = new ArrayList<>();
//new Vector<>();
//Collections.synchronizedList(new ArrayList<>());
//new CopyOnWriteArrayList<>();
for (int i = 1; i <= 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
}, String.valueOf(i)).start();
}
- 当 i 即线程数过高时,
ArrayList
是非线程安全的容器,会出现java.util.ConcurrentModificationException
故障问题,可以使用以上三种方法解决问题。 CopyOnWriteArrayList
容器即写时复制的容器。- 一个容器添加元系的时候,不直接往当前容器
Object[]
添加,而是先将当前容器Object[]
进行Copy
,复制出一个新的容器Object[] newELements
,然后新的容器Object[] newELements
里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray( newELements);
。这样做的好处是可以对CopyOnWrite
容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite
容器也是一种读写分离的思想,读和写不同的容器
- 一个容器添加元系的时候,不直接往当前容器
set 不安全
Set<String> set = new HashSet<>();
//Collections.synchronizedSet(new HashSet<>());
//new CopyOnWriteArraySet<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
}, String.valueOf(i)).start();
}
HashSet
底层是HashMap
,但HashSet
只有一个值,HashMap
有两个值,是因为HashMap
传进HashSet
的是 key 的值,而 value 是一个写死的常量。
map 不安全
Map<String, String> map = new HashMap<>();
//Collections.synchronizedMap()
//new ConcurrentHashMap();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
System.out.println(map);
}, String.valueOf(i)).start();
}
Callable 接口
class MyThread implements Runnable{
@Override
public void run() {
}
}
class MyThread2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return null;
}
}
Callable接口:第3种获得多线程的方式
- 异同:
- 方法不同:一个是run,一个是call
- 异常不同:Runnable没异常,Callable抛异常
- 返回值不同:Runnable没返回值,Callable有返回值
/*MyThread myThread = new MyThread();// implements Callable<Integer>
Thread t1 = new Thread(myThread);
t1.start();*/
FutureTask futureTask = new FutureTask(new MyThread());
- 调用Callable接口时不能使用new Thread(myThread),因为Thread中要传入Runnable参数,不能传Callable,所以要用FutureTask来实现Runnable和Callable接口,传入Callable参数
JUC的辅助类
CountDownLatch(减少计数)
CountDownLatch
主要有两个方法,- 当一个或多个线程调用 await方法时,这些线程会阻塞。
- 其它线程调用 countDown方法会将计数器减1(调用 countDown方法的线程不会阻塞),当计数器的值变为8时,因 await方法阻塞的线程会被唤醒,继续执行。
CyclicBarrier(循环栅栏)
Semaphore(信号灯)
- 在信号量上我们定义两种操作:
- acquire(获取)当一个线程调用 acquire操作时,它要么通过成功获取信号量(信号量减1),
要么一直等下去,直到有线程释放信号量,或超时 - release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。
- acquire(获取)当一个线程调用 acquire操作时,它要么通过成功获取信号量(信号量减1),
- 信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。
ReentrantReadWriteLock(读写锁)
/**
* 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行
* 但是
* 如果有一个线程想去写共享资源来,就不应该再有其它线程可以对该资源进行读或写
* 小总结:
* 读-读能共存
* 读-写不能共存
* 写-写不能共存
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
BlockingQueue(阻塞队列)
- 在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤起;
- 好处:我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程。
ThreadPool线程池(ThreadPoolExecutor)
- 线程池的优势:
线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。 - 主要特点:线程复用;控制最大并发数;管理线程。
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。
- 提髙线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
七大参数
- 1、常驻线程;2、最大线程数;3、存活时间;4、时间单位;5阻塞队列;6、线程工厂;7、拒绝策略。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
设置合理参数-拒绝策略
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
2L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
//new ThreadPoolExecutor.AbortPolicy());
//new ThreadPoolExecutor.CallerRunsPolicy());
//new ThreadPoolExecutor.DiscardPolicy());
new ThreadPoolExecutor.DiscardOldestPolicy());
四大函数式接口
/*Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return 1024;
}
};
System.out.println(function.apply("abc"));*/
Function<String, Integer> function = s -> {return s.length();};
System.out.println(function.apply("abc"));
/*Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String s) {
return false;
}
};*/
Predicate<String> predicate = s -> {return s.isEmpty();};
System.out.println(predicate.test("abcde"));
/*Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
}
};*/
Consumer<String> consumer = s -> { System.out.println(s); };
consumer.accept("abcde");
/*Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return null;
}
};*/
Supplier<String> supplier = () -> {return "java12.22";};
System.out.println(supplier.get());
/*-------------------------------------------------------------------------------------------------*/
输出:
3
false
abcde
java12.22