集合类不安全
List不安全
package com.zhang.unsafe;import java.util.*;import java.util.concurrent.CopyOnWriteArrayList;//并发修改异常public class ListTest {public static void main(String[] args) {//并发下ArrayList是不安全的/*** 解决方案:* 1. List<String> list = new Vector<>(); Vector默认就是安全的,出现于1.0 ArrayList默认是非安全的,出现于1.8** 2. List<String> list = Collections.synchronizedList(new ArrayList<>());** 3. List<String> list = new CopyOnWriteArrayList<>(); JUC下的* */// CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略//多个线程调用的时候,list,读取的时候是固定的,写入的时候不能让其同时在上面去写,会造成覆盖//写入的时候避免覆盖,造成数据问题//CopyOnWriteArrayList 比 Vector 优于哪里?Vector使用的是Synchronized,CopyOnWriteArrayList使用lock锁,性能高于VectorList<String> 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();}}}
set不安全
package com.zhang.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** 解决方案 :1.Set<String> set = Collections.synchronizedSet(new HashSet<>());** 2.Set<String> set = new CopyOnWriteArraySet<>();* */public class SetTest {public static void main(String[] args) {//Set<String> set = new HashSet<>();//Set<String> set = Collections.synchronizedSet(new HashSet<>());Set<String> set = new CopyOnWriteArraySet<>();for (int i = 0; i < 30; i++) {new Thread(()->{set.add(UUID.randomUUID().toString().substring(0,5));System.out.println(set);},String.valueOf(i)).start();}}}
public HashSet() {map = new HashMap<>();}//add set的本质就是map的key,因为key是不可以重复的public boolean add(E e) {return map.put(e, PRESENT)==null;}//PRESENT 是一个常量,固定的值private static final Object PRESENT = new Object();
Map不安全

package com.zhang.unsafe;import java.util.HashMap;import java.util.Map;import java.util.UUID;import java.util.concurrent.ConcurrentHashMap;//ConcurrentModificationExceptionpublic class MapTest {public static void main(String[] args) {//map是这样使用的吗?不是,工作中不用HashMap//默认等价什么?new HashMap<>(16,0.75f)//Map<String, Object> map = new HashMap<>();//负载因子(默认是0.75)、初始化容量(1<<4 16)Map<String, String> map = new ConcurrentHashMap<>();for (int i = 0; i <=30; i++) {new Thread(()->{map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));System.out.println(map);}).start();}}}
Callable

可以有返回值
可以抛出异常
方法不同,run()/call()
package com.zhang.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) throws ExecutionException, InterruptedException {//1. 传统方法//new Thread(new MyThread()).start();//new Thread(new FutureTask<V>()).start();//new Thread(new FutureTask<V>(Callable)).start();//new Thread().start();//怎么启动CallableMyThread thread = new MyThread();//适配类FutureTask futureTask = new FutureTask(thread);//thread的返回值会被futureTask接受new Thread(futureTask,"A").start();new Thread(futureTask,"B").start();//只会输出一个call(),结果会被缓存,效率高String o = (String) futureTask.get();//获取Callable的返回结果;这个get方法可能会产生阻塞,把它放到最后,或者使用异步通信来处理System.out.println(o);}}//泛型的参数等于方法的返回值class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {System.out.println("call()");//耗时的操作return "123";}}//1. 传统方式/*class MyThread implements Runnable{@Overridepublic void run() {}}*/
常用辅助类
CountDownLatch

package com.zhang.add;import java.util.concurrent.CountDownLatch;//计数器(减法)public class DountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//总数是6,用于倒计时,CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 0; i < 6; i++) {new Thread(()->{System.out.println(Thread.currentThread().getName()+"go out");countDownLatch.countDown();//-1},String.valueOf(i)).start();}countDownLatch.await();//等待计数器归零,然后再向下执行,用于必须要执行的任务时System.out.println("Close door");//countDownLatch.countDown();//-1}}
原理:
countDownLatch.countDown(); -1
countDownLatch.await();//等待计数器归零,然后再向下执行
每次有线程调用countDown()数量-1,假设计数器变为0,countDownLatch.await()就会被唤醒,继续执行。
CycliBarrier

package com.zhang.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 = 0; i < 7; i++) {final int temp = i;//lambda不能操作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.zhang.add;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;public class SemaphoreDemo {public static void main(String[] args) {//限流//线程数量:停车位Semaphore semaphore = new Semaphore(3);for (int i = 0; i <= 6; i++) {new Thread(()->{try {semaphore.acquire();//acquire(),得到System.out.println(Thread.currentThread().getName()+"抢到车位");TimeUnit.SECONDS.sleep(3);//停留时间System.out.println(Thread.currentThread().getName()+"离开车位");} catch (InterruptedException e) {e.printStackTrace();}finally {semaphore.release();//release()释放}},String.valueOf(i)).start();}}}
原理:
semaphore.acquire();获得,假设如果已经满了,等待被释放为止
semaphore.release() 释放,会将当前的信号量释放,然后唤醒等待的线程
作用:多个共享资源互斥的使用!并发限流,控制最大的线程数
读写锁( ReadWriteLock)

package com.zhang.rw;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/*** 独占锁(写锁) 一次只能被一个线程占有* 共享锁(写锁) 多个线程可以同时占有* ReadWriteLock* 读-读 可以共存* 读-写 不能共存* 写-写 不能共存*/public class ReadWriteLockDemo {public static void main(String[] args) {//MyCache myCache = new MyCache();MyCacheLock myCache = new MyCacheLock();//写入for (int i = 1; i <= 5; i++) {final int temp = i;new Thread(()->{myCache.put(temp+"",temp+"");},String.valueOf(i)).start();}//读取for (int i = 1; i <= 5; i++) {final int temp = i;new Thread(()->{myCache.get(temp+"");},String.valueOf(i)).start();}}}//加锁的class MyCacheLock{private volatile Map<String,Object> 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);Object o = map.get(key);System.out.println(Thread.currentThread().getName()+"读取OK"+key);} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.readLock().unlock();}}}/*自定义缓存 set get*/class MyCache{private volatile Map<String,Object> map = new HashMap<>();//存 ,写public void put(String key,Object value){System.out.println(Thread.currentThread().getName()+"写入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入OK"+key);}//取,读public void get(String key){System.out.println(Thread.currentThread().getName()+"读取"+key);Object o = map.get(key);System.out.println(Thread.currentThread().getName()+"读取OK"+key);}}

文章转载自爱德华的奇妙生活,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




