JUC并发编程02

JUC并发编程01

7、Callable

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同,run()/call()
    示例
public class Callabletest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// new Thread(new Runable()).strat;
		// new Thread(new FutureTask<V>()).start; FutureTask实现了Runable接口,
		// FutureTask的构造方法
		// FutureTask(Callable<V> callable);FutureTask(Runable runable, V result);
		// new Thread(new FutureTask<V>(Callabel)).start;  **适配器模式**
		Callable<String> callable = new MyThread();
		FutureTask<String> futureTask = new FutureTask<String>(callable);// 适配类
		new Thread(futureTask,"A").start(); // 同一个FutureTask只会执行一次
		new Thread(futureTask,"B").start();
		String str = futureTask.get();//  会阻塞
		System.out.println(str);
	}
}
class MyThread implements Callable<String> {
	@Override
	public String call() throws Exception {
		System.out.println("call()");
		return "hello";
	}
}

8、常用的辅助类

8.1、CountDownLatch
public class CountDownLatchDemo {
	// 计数器
	public static void main(String[] args) throws Exception {
		CountDownLatch countDownLatch = new CountDownLatch(6);// 计数初始化
		for (int i = 1; i <= 6; i++) {
			new Thread(()->{
				System.out.println(Thread.currentThread().getName()+" execute");
				countDownLatch.countDown();
			}).start();
		}
		countDownLatch.await();// 阻塞直到countDown()方法的调用导致当前计数达到零,之后所有等待线程被释放,并且后续的await调用立即放回
		//countDownLatch.await(5,TimeUnit.SECONDS); 等待5秒主线程执行,如果上面的异常发生异常不会被主线程捕获
		System.out.println("game over");
	}
}
8.2、CyclicBarrier
public class CylicBarrierDemo {
	// 加法计数器
	public static void main(String[] args) throws Exception {
		CyclicBarrier barrier = new CyclicBarrier(6,()->{
			System.out.println("you turn");
		});
		for (int i = 1; i <= 5; i++) {
			new Thread(()->{
				System.out.println(Thread.currentThread().getName()+" execute");
				try {
					barrier.await();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
			}).start();
		}
	}
}

8.3、Semaphore(信号量)

作用:多个共享资源互斥的使用,并发限流,控制最大线程数

public class SemaphoreDemo {
	// 加法计数器
	public static void main(String[] args) throws Exception {
		Semaphore semaphore = new Semaphore(3);
		for (int i = 1; i < 7; i++) {
			new Thread(() -> {
				try {
					semaphore.acquire();// 获取许可证,如果沒有了继续等待
					System.out.println(Thread.currentThread().getName() + " in");
					TimeUnit.SECONDS.sleep(2);
					System.out.println(Thread.currentThread().getName() + " out");
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					semaphore.release();// 释放许可证,会将当前的信号量释放+1,等待的线程获取信号量进入执行
				}
			}).start();
		}
	}
}

9、读写锁(ReadWriteLock)

疑问:使用场景

public class ReadWriteLockDemo {
	public static void main(String[] args) {
		MycaheLock mycaheLock = new MycaheLock();
		// 读线程
		for (int i = 0; i < 5; i++) {
			final int temp = i;
			new Thread(()->{
				mycaheLock.get(String.valueOf(temp));
			}).start();
		}
		// 写线程
		for (int i = 0; i < 5; i++) {
			final int temp = i;
			new Thread(()->{
				mycaheLock.put(String.valueOf(temp), temp);
			}).start();
		}
	}
}
class MycaheLock {
	private volatile Map<String, Object> map = new HashMap<>();
	// 读写锁
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

	public void put(String key, Object value) {
		readWriteLock.writeLock().lock();// lock需要在finally中手动释放
		try {
			System.out.println(Thread.currentThread().getName() + "写入" + key);
			map.put(key, value);
			System.out.println(Thread.currentThread().getName() + "写入OK");
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}

	// 取/读 所有人都可以读
	public void get(String key) {
		readWriteLock.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + "读取" + key);
			Object object = map.get(key);
			System.out.println(Thread.currentThread().getName() + "读取OK" + object);
		} finally {
			readWriteLock.readLock().unlock();
		}
	}
}

10、阻塞对列(FIFO)线程安全

1、如果对列满了,阻塞等待读取
2、如果对列是空的,阻塞等待写入
BlockingQuene(接口)
实现ArrayBlockingQuene,LinkedBlockingQuene,SynchronousQuene同步对列
结构图
对列操作:添加,删除
四组API

  1. 抛出异常
  2. 不会抛出异常
  3. 阻塞等待
  4. 超时等待
方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加addoffer()put()offer(…)
移除removepoll()take()poll(…)
检测队首元素element()peek()--
class BlockingQueneAPI {

	private ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
	// 有返回值,抛出异常
	public void test1() {
		System.out.println(blockingQueue.add("A"));
		System.out.println(blockingQueue.add("B"));
		System.out.println(blockingQueue.add("C"));
		// System.out.println(blockingQueue.add("D"));
		System.out.println("====================");
		// 获取头部元素
		System.out.println(blockingQueue.element());
		System.out.println(blockingQueue.remove());
		System.out.println(blockingQueue.remove());
		System.out.println(blockingQueue.remove());
		//System.out.println(blockingQueue.remove());
	}

	// 有返回值,不抛出异常
	public void test2() {
		System.out.println(blockingQueue.offer("A"));
		System.out.println(blockingQueue.offer("B"));
		System.out.println(blockingQueue.offer("C"));
		System.out.println(blockingQueue.offer("D"));
		System.out.println("====================");
		// 获取头部元素
		System.out.println(blockingQueue.peek());
		System.out.println(blockingQueue.poll());
		System.out.println(blockingQueue.poll());
		System.out.println(blockingQueue.poll());
		System.out.println(blockingQueue.poll());
	}

	// 阻塞等待
	public void test3() throws InterruptedException {
		// 添加无返回值
		blockingQueue.put("A");
		blockingQueue.put("B");
		blockingQueue.put("C");
		// System.out.println(blockingQueue.take());
		// blockingQueue.put("D");// 对列没有位置了,会一直阻塞
		System.out.println("====================");
		// 获取头部元素
		System.out.println(blockingQueue.take());
		System.out.println(blockingQueue.take());
		System.out.println(blockingQueue.take());
		// System.out.println(blockingQueue.take());// 对列空了,会一直阻塞
	}

	// 超时等待
	public void test4() throws InterruptedException {
		System.out.println(blockingQueue.offer("A",2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.offer("B",2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.offer("C",2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.offer("D",2,TimeUnit.SECONDS));// 两秒之后退出阻塞
		System.out.println("====================");
		// 获取头部元素
		System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
		System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));// 两秒之后退出阻塞
	}
}

同步对列(SynchronousQuene)
没有容量,不存储元素
存入一个元素,必须取出才能放入另一个元素

public class SynchronousQueneDemo {
	public static void main(String[] args) {
		SynchronousQueue<String> queue = new SynchronousQueue<String>();

		new Thread(() -> {
			try {
				System.out.println(Thread.currentThread().getName() + "放入1");
				queue.put("1");
				System.out.println(Thread.currentThread().getName() + "放入2");
				queue.put("2");
				System.out.println(Thread.currentThread().getName() + "放入3");
				queue.put("3");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}).start();

		new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "取出" + queue.take());
				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "取出" + queue.take());
				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "取出" + queue.take());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
	}
}

11、线程池

池化技术的优点:有利于资源的管理,降低资源消耗,提高响应速度(创建和销毁)
线程池的作用:线程复用,控制最大并发数,管理线程

11.1三大方法、7大参数,四种拒绝策略

三大方法:
Excutors.new SingleThreadExcutors();// 对列长度Integer.MAX_VALUE ,导致OOM
Excutors.new FixedThreadExcutors();// 对列长度Integer.MAX_VALUE ,导致OOM
Excutors.new CacheThreadExcutors();// 线程个数Integer.MAX_VALUE, 导致OOM
7大参数:
使用ThreadPoolExecutor构造线程池:

public ThreadPoolExecutor(int corePoolSize,// 常驻核心线程数
                              int maximumPoolSize,// 最大线程数
                              long keepAliveTime,// 线程空闲时间,当线程时间达到keepAliveTime值时,线程会被销毁,直到剩下corePoolSize个线程
                              TimeUnit unit,// 时间单位,配合线程空闲时间使用
                              BlockingQueue<Runnable> workQueue,// 缓存队列,当请求的线程数大于核心线程数加入缓存队列,如果缓存队列已满,并且maximumPoolSize>corePoolSize,创建新线程,如果达到了maximumPoolSize,新来的请求由拒绝策略处理
                              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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

四种拒绝策略:

  1. new ThreadPoolExecutor.AbortPolicy() // 不处理,抛出异常
  2. new ThreadPoolExecutor.CallerRunsPolicy() // 调用任务的run()方法绕过线程池执行
  3. new ThreadPoolExecutor.DiscardPolicy() // 丢掉任务,不会抛出异常
  4. new ThreadPoolExecutor.DiscardOldestPolicy() //抛弃队列中等待最久的任务,然后把当前任务加入队列
    拓展
    池的最大的大小如何去设置!
    了解:IO密集型,CPU密集型:(调优)
    最大线程到底该如何定义
    1、CPU 密集型,设置为设备CPU和数,可以保持CPU的效率最高
    2、IO 密集型,大于程序中十分耗IO的线程数量
    获取CPU的核数 System.out.println(Runtime.getRuntime().availableProcessors());
11.2 手动创建线程池
public static void main(String[] args) {
		ThreadPoolExecutor executor = new ThreadPoolExecutor(
				2, // 核心
				5, // 最大
				2, // 存活时间,只有线程数>核心线程数
				TimeUnit.SECONDS, 
				new LinkedBlockingQueue<>(3),
				Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.DiscardOldestPolicy());// 这是内部类吗
		try {
			// 最大承载:Queue + max
			// 超过之后使用拒绝策略处理
			for (int i = 1; i < 10; i++) {
				final int temp = i;
				executor.execute(()->{
					System.out.println(Thread.currentThread().getName()+ ": "+temp);
				});
			}
		} finally {
			executor.shutdown();
		}
	}

12、四大函数式接口

Function<T(传入参数),R(返回参数)>()
在这里插入图片描述
特性:
有一个输入,有一个输出;
可以用lambda表达式简化 ()->{};

public static void main(String[] args) {
		Function<String, String> function = new Function<String, String>() {
			@Override
			public String apply(String t) {
				return t;
			}
		};
		// 简化
		Function<String, String> function1 = (str)->{return str;};
		System.out.println(function1.apply("12121"));
	}

Predicate 断定型接口 判断字符串是否为空

public static void main(String[] args) {
		Predicate<String> predicate = new Predicate<String>() {
			@Override
			public boolean test(String t) {
				return t.isEmpty();
			}
		};
		Predicate<String> predicate1 = (t)->{return t.isEmpty();};
		System.out.println(predicate1.test(""));
	}

Consumer 消费型接口:只有输入,没有返回

public static void main(String[] args) {
		Consumer<String> consumer = new Consumer<String>() {
			@Override
			public void accept(String t) {
				System.out.println(t);
			}
		};
		Consumer<String> consumer2 = (t)->{System.out.println(t);};
		consumer2.accept("hello, world");
	}

Supplier 供给型接口:没有参数,只有返回值

public static void main(String[] args) {
		Supplier<String> supplier = new Supplier<String>() {
			@Override
			public String get() {
				return "hello";
			}
		};
		Supplier<String> supplier2 = ()->{return "hello";};
		System.out.println(supplier2.get());
	}

comparator也是函数式接口

13、Stream流式计算

什么是Stream流式计算
大数据:存储+计算
集合,Mysql本质:存储东西
计算交给流处理
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值