Java并发篇一

CopyOnWriteArrayList

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<String> list=new ArrayList<>();
        // 解决方案
        // 一:List<String> list=new Vector<>();
        // 二:List<String> list= Collections.synchronizedList(new ArrayList<>());
        // 三:List<String> list=new CopyOnWriteArrayList<>();
        // CopyOnWrite 写入时复制
        // 在写入的时候避免覆盖,出现数据问题
        List<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();
        }

    }
}

多个线程调用的时候,读取时是固定的,写入时可能会发生覆盖,所以计算机程序设计领域优化的策略是使用CopyOnWriteArrayList 

CopyOnWriteArraySet

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<String> set=new HashSet<>();
        //Set<String> set= Collections.synchronizedSet(new HashSet<>());
        Set<String> 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();//不变的值

ConcurrentHashMap

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<String,String> map = new HashMap<>();
        Map<String,String> 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();
        }
    }
}

Callable(简单)与Runnable相比

  • 可以有返回值
  • 可以抛出异常
  • 方法不同,call() 

走近Callable 

Runnable和Callable实现类有:FutureTask 

细节:有缓存、结果可能需要等待,会阻塞 

new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("run()");
    }
}.start();

new Thread(new FutureTask<V>()).start();
new Thread(new FutureTask<V>(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<Integer> 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<Integer>{

    @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,唤醒等待的线程

ReadWriteLock读写锁

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<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);
            map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取OK");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            readWriteLock.readLock().unlock();
        }
    }

}

阻塞队列BlockingQueue 非阻塞队列AbstractQueue 双端队列Deque

/**
     * 抛出异常
     */
    public static void test1(){
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        arrayBlockingQueue.add("a");
        arrayBlockingQueue.add("b");
        arrayBlockingQueue.add("c");
        // java.lang.IllegalStateException: Queue full
        // arrayBlockingQueue.add("d");
        System.out.println("------------");
        System.out.println(arrayBlockingQueue.remove());
        System.out.println(arrayBlockingQueue.remove());
        System.out.println(arrayBlockingQueue.remove());
        // java.util.NoSuchElementException
        // System.out.println(arrayBlockingQueue.remove());
    }
/**
     * 有返回值,不抛出异常
     */
    public static void test2(){
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(arrayBlockingQueue.offer("a"));//true
        System.out.println(arrayBlockingQueue.offer("b"));//true
        System.out.println(arrayBlockingQueue.offer("c"));//true
        System.out.println(arrayBlockingQueue.offer("d"));//false
        System.out.println("------------");
        System.out.println(arrayBlockingQueue.poll());//a
        System.out.println(arrayBlockingQueue.poll());//b
        System.out.println(arrayBlockingQueue.poll());//c
        System.out.println(arrayBlockingQueue.poll());//null
    }
/**
     * 等待,一直阻塞
     */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        arrayBlockingQueue.put("a");
        arrayBlockingQueue.put("b");
        arrayBlockingQueue.put("c");
//        arrayBlockingQueue.put("d");
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take());
//        System.out.println(arrayBlockingQueue.take());
    }
/**
     * 超时等待,过时就不等
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        arrayBlockingQueue.offer("a");
        arrayBlockingQueue.offer("b");
        arrayBlockingQueue.offer("c");
        arrayBlockingQueue.offer("d",2, TimeUnit.SECONDS);//超过2s就不等待了
        System.out.println("---------");
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll(2,TimeUnit.SECONDS));
    }
方式 抛出异常 有返回值,不抛异常 等待 超时等待
添加 add() offer() put() offer(,,)
移除 remove() poll() take() poll(,)
检测队首元素 element() peek() - -

SynchronousQueue同步队列

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

CPU密集型和IO密集型(调优)

System.out.println(Runtime.getRuntime().availableProcessors());//获取CPU核数

最大线程数如何设置

CPU密集型:几核就定义几,可以保持CPU效率高

IO密集型:大于判断非常耗IO的线程 通常设置其2倍(程序 15个大型任务 io非常占用资源,这里我们设置其2倍即30)

函数式接口(4个基本)

函数型接口 有一个输入参数,有一个输出

package com.kuang.function;

import java.util.function.Function;
// 函数型接口 泛型有一个输入参数,有一个输出
// 只要是函数型接口,都可以用Lambda表达式简化
public class Demo01 {
    public static void main(String[] args) {
        /*Function<String,String> function=new Function<String, String>() {
            @Override
            public String apply(String str) {
                return str;
            }
        };*/
        Function<String,String> 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<String> predicate=new Predicate<String>() {
            @Override
            public boolean test(String str) {
                return str.isEmpty();
            }
        };*/
        Predicate<String> 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<String> consumer=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };*/
        Consumer<String> 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<Integer>() {
            @Override
            public Integer get() {
                System.out.println("get()");
                return 1024;
            }
        };*/
        Supplier<Integer> supplier=()->{
            System.out.println("get()");
            return 1024;
        };
        System.out.println(supplier.get());
    }
}

链式编程(这里不讲)+Stream流式计算

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

猜你喜欢

转载自blog.csdn.net/bubbleJessica/article/details/129918540