Java多线程进阶
参考www.cnblogs.com/hlkawa/tag/JAVA多线程/
一、并发和阻塞队列
1、CountDownLatch类
实现类似计数器的功能,如在前4个线程执行完后再执行主线程,区别于this.wait/notify使用在类中。
CountDownLatch countDownLatch = new CountDownLatch(2); countDownLatch.countDown(); countDownLatch.await(); //当前计数为0时才被唤醒
2、CyclicBarrier
顾名思义:线程到齐后才能跨越这个障碍
await唤醒方式对比:CountDownLatch CyclicBarrier
当前计数减至0 当先等待状态的进程数目是3时,则这3个进程被唤醒。
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
()->{ cyclicBarrier.await();
...do something...
}
3、信号量机制Semaphore
概念:基于计数,可设置阈值n,m个线程竞争n个信号(m > n),超过阈值时申请的信号会被阻塞。
功能:用以构建一些对象池、资源池,如数据库连接池;n=1时为互斥锁。
Semaphore sp = new Semaphore(4); ()->{ int availablePermits = sp.availablePermits(); //当前剩余可获取的信号量数 sp.acquire(); sp.release(); }
4、阻塞队列
概念:生产者消费者问题中,队列容量为10,size在0到10之外时需要this.wait和this.notifyAll(), 而且offer/poll之外需要synchronized。
顾名思义 阻塞队列在容量外自行阻塞(队列中不得存入null)
作用:线程安全的 很好地解决了多线程之间通信的问题。
BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10); AtomicInteger atomicInteger = new AtomicInteger(); String data = atomicInteger.incrementAndGet() + ""; boolean flag = queue.offer(data, 2, TimeUnit.SECONDS); String data = queue.poll(2, TimeUnit.SECONDS); if(data != null) System.out.println(">消费者取出 " + data + "\tSuccess.");

import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class BlockingQueueThread { private static boolean flag = true; public static void main(String[] args) throws InterruptedException { BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10); AtomicInteger atomicInteger = new AtomicInteger(); for(int i = 0; i < 3; i++){ new Thread(new Runnable() { @Override public void run() { while (flag){ String data = atomicInteger.incrementAndGet() + ""; try { boolean flag = queue.offer(data, 2, TimeUnit.SECONDS); if(flag) System.out.println("*生产者" + Thread.currentThread().getName() + "存入 " + data + "\tSuccess."); else System.out.println("*生产者" + Thread.currentThread().getName() + "存入 " + data + "\tFailed."); } catch (InterruptedException e) { e.printStackTrace(); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // Thread.sleep(100) } } }).start(); } for(int i = 0; i < 2; i++){ new Thread( ()->{ while (flag){ try { String data = queue.poll(2, TimeUnit.SECONDS); if(data != null) System.out.println(">消费者" + Thread.currentThread().getName() + "取出 " + data + "\tSuccess."); else System.out.println(">消费者" + Thread.currentThread().getName() + "取出 " + data + "\tFailed."); } catch (InterruptedException e) { e.printStackTrace(); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // Thread.sleep(100) } } ).start(); } Thread.sleep(100 * 5); flag = false; } }
二、线程池和锁分类
概念:以线程重用技术避免反复创建与销毁。
优点:①降低资源损耗; ②提高响应速度; ③提高线程可管理性(方便线程的统一分配、调优、监控,提高系统稳定性)。
使用范围:短时间内线程大量爆发的场景,高实时响应的任务中。

Executors工厂类提供4个方法,newSingleThreadExecutor()、newFixedThreadPool(3)、newCachedThreadPool()和newScheduledThreadPool
即顶层实现的ThreadPoolExecutor类构造方法参数不同。
public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); for (int i=1;i<= 20;i++) { int count = i; threadPool.execute(new Runnable() { @Override public void run() { System.out.println("当前执行任务的线程是 "+ Thread.currentThread().getName() + " [ i ="+ count + "]"); } }); } }
参数
corePoolSize: 核心线程数、核心池大小 <= cpu_n
maximumPoolSize: 线程池最大线程数 ∈[cpu_n + 1, 2 * cpu_n] cpu密集型 -> IO密集型。
keepAliveTime:没有任务执行的线程能存活的时间
unit: keepAliveTime的时间单位
原理——一个用户任务提交至线程池,处理流程如下:
①判断池中核心线程中是否都忙,有空闲则直接执行,否则下一步
②判断池中缓存队列是否已满,有空闲则把任务加入队列中等待执行,否则下一步
③判断池中所有线程是否都忙,有空闲则创建新工作线程执行,否则交给饱和策略。
锁的基本分类
①悲观锁:每次取数据时都认为其它京城会修改,造成更新丢失。如synchronized, lock锁,mysql的行锁。
②公平锁:线程先来先服务FIFO获取锁。synchronized是非公平的,(线程)谁抢到归谁 效率更高。
③独占锁:仅允许一个线程持有,其它线程都会等待 如synchronized; 共享锁:多个进程同时持有锁。
eg:读写锁中"读-读"共享,其它互斥
import java.util.concurrent.locks.ReentrantReadWriteLock; //读写锁 static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); static Lock r = lock.readLock(); static Lock w = lock.writeLock();

package com.kawa.thread.myStudy; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * TODO * * @author Administrator * @version 1.0 * @date 2022/3/29 13:29 */ public class ReadWriteLock { static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); static Lock r = lock.readLock(); static Lock w = lock.writeLock(); static Map<String, Object> h = new HashMap<String, Object>(); public static void put(String attr, Object o){ w.lock(); h.put(attr, o); System.out.println(o + "\tis putted."); w.unlock(); } public static Object get(String attr){ r.lock(); Object o = h.get(attr); System.out.println(o + "\tis getted**."); r.unlock(); return o; } public static void main(String[] args){ new Thread( ()->{ for(int i = 0; i < 5; i++) ReadWriteLock.put(i + "", "hello " + i); } ).start(); new Thread( ()->{ for(int i = 0; i < 5; i++) ReadWriteLock.get(i + ""); } ).start(); } }
④重入锁:也叫递归锁,外层函数获得锁之后,内层递归函数一样获取;如synchronized。