JUC
进程与线程。
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。
Java默认有两个线程,Main线程和GC线程。
Java本身其实是不能开启线程的,当我们调用线程的start()方法时候,其实底层调用的是下面的方法(C++方法)
private native void start0();
并发与并行
并发:针对的是单核CPU。(CPU在同一时间只能处理一个任务)所谓并发,就是通过一种算法将 CPU 资源合理地分配给多个任务,当一个任务执行 I/O 操作时,CPU 可以转而执行其它的任务,等到 I/O 操作完成以后,或者新的任务遇到 I/O 操作时,CPU 再回到原来的任务继续执行。
并行:针对多核CPU。(多个线程可以同时执行)多核 CPU 的每个核心都可以独立地执行一个任务,而且多个核心之间不会相互干扰。在不同核心上执行的多个任务,是真正地同时运行,这种状态就叫做并行。
并发编程的本质:充分利用CPU资源。
线程的状态
Thread.State 该枚举类定义了线程的集中状态。
public enum State {
/**
* 线程新生
*/
NEW,
/**
* 运行状态
*/
RUNNABLE,
/**
* 阻塞状态(线程阻塞于锁)
*/
BLOCKED,
/**
* 等待状态(一直等)
*/
WAITING,
/**
* 指定了等待时间的等待状态(超时等待,过期不候)
*/
TIMED_WAITING,
/**
* 已终止线程的线程状态。线程已完成执行。
*/
TERMINATED;
}
run()和start()
run()只是普通的方法调用,有主线程执行代码,并没有开启新线程。
start() 新开辟线程执行。起到了多线程异步的效果。
sleep()和wait()
wait() 属于Object.java、会释放锁、只能在同步代码块中使用(因为他需要锁)
sleep()属于Thread.java、不会释放锁、可以在任何地方使用。
sleep小妙用防止cpu占用达到100%
避免while(true)空转浪费CPU资源
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sleep() 和 yield()
sleep():
调用sleep()会让当前线程从RUNNABLE状态进入TIMED_WAITING状态。
其他线程可以使用interrupt()方法打断正在睡眠的线程,这是sleep发放会抛出异常(InterrupteException)。
睡眠结束后线程未必会立刻得到执行。
建议使用TimeUnit 的 sleep 代替Thread的sleep 获取更好的可读性。
yield()
调用yield()方法 让线程从RUNNING(java线程并没有running状态,此处只表示线程正在执行)状态到RUNNABLE状态,然后cpu调度其他同优先级的线程,要是没有其他线程可调用,不能保证实现线程暂停的效果。
具体的实现依赖于操作系统的任务调度器。
synchronized 和 Lock
synchronized 是内置关键字;Lock是接口。
synchronized 无法判断获取锁的状态;Lock可以判断是否获取到锁。
synchronized 自动释放锁;Lock需要手动释放锁。
synchronized 线程1(获得锁,阻塞),线程2(等待,一直等);Lock不一定一直等tryLock()方法尝试获取锁。
synchronized 可重入锁,不可中断的,非公平;Lock 可重入锁,可以判断锁,非公平(可自己设置)。
synchronized 适合锁少量的代码同步问题;Lock 适合锁大量的代码同步问题。
生产者消费者
传统:
class Data {
private int data = 0;
public synchronized void increment() throws InterruptedException {
//此处用while 解决虚假唤醒问题,不能用if(if 只执行一次)
while (data != 0) {
//等待
this.wait();
}
data++;
System.out.println(Thread.currentThread().getName() + "-->+1--结果---" + data);
//通知其他线程+1完成
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
//此处用while 解决虚假唤醒问题,不能用if
while (data == 0) {
//等待
this.wait();
}
data--;
System.out.println(Thread.currentThread().getName() + "-->-1--结果---" + data);
//通知其他线程-1完成
this.notifyAll();
}
}
public class ProductAndConsumer {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Data2 {
private int data = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
//此处用while 解决虚假唤醒问题,不能用if(if 只执行一次)
while (data != 0) {
//等待
condition.await();
}
data++;
System.out.println(Thread.currentThread().getName() + "-->+1--结果---" + data);
//通知其他线程+1完成
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
//此处用while 解决虚假唤醒问题,不能用if
while (data == 0) {
//等待
condition.await();
}
data--;
System.out.println(Thread.currentThread().getName() + "-->-1--结果---" + data);
//通知其他线程-1完成
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
线程顺序执行
/**
* 让三个线程顺序执行:A->B->C (精确通知)
*/
class Data3 {
private int data = 1;
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void printA() throws InterruptedException {
lock.lock();
try {
while (data != 1) {
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "printA---data = " + data);
data = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() throws InterruptedException {
lock.lock();
try {
while (data != 2) {
//等待
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "printB---data = " + data);
data = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() throws InterruptedException {
lock.lock();
try {
while (data != 3) {
//等待
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "printC---data = " + data);
data = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
集合类不安全
list不安全
public static void listTest1(){
//ConcurrentModificationException :并发修改异常
//并发下arrayList 不安全
List<String> list1 = new ArrayList();
//⭐️ArrayList可以转为线程安全的,下面的list2 再操作便不会报ConcurrentModificationException
List<Object> list2 = Collections.synchronizedList(new ArrayList());
//⭐️Vector在多线程中是安全的。Vector中add方法有synchronized修饰。
List<String> list3 = new Vector<>();
//CopyOnWriteArrayList 也是线程安全的集合:(写入时复制 COW 计算机程序设计领域的优化策略)
//写入的时候避免覆盖,造成数据问题。
//CopyOnWriteArrayList 比 Vector 厉害的点:
//Vector 被 synchronized修饰 CopyOnWriteArrayList用的是Lock锁 CopyOnWriteArrayList 效率高于 Vector
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(Thread.currentThread().getName() + "--->" + list);
}, String.valueOf(i + 1)).start();
}
}
CopyOnWriteArrayList 的add()源码
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
Set 不安全 (同ArrayList)
public static void setTest1(){
//ConcurrentModificationException :并发修改异常
//并发下 HashSet 不安全
Set<String> set1 = new HashSet<>();
//⭐HashSet 可以转为线程安全的,下面的set2 再操作便不会报ConcurrentModificationException
Set<String> set2 = Collections.synchronizedSet(new HashSet());
//CopyOnWriteArraySet 也是线程安全的集合:(写入时复制 COW 计算机程序设计领域的优化策略)
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + "--->" + set);
}, String.valueOf(i + 1)).start();
}
}
HashSet是什么?
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
//add PRESENT 就是一个不变的虚拟值。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
HashSet 底层就是HashMap.利用了Map的 key不重复。
Map 不安全
public static void mapTest1(){
//ConcurrentModificationException :并发修改异常
//并发下 HashMap 不安全
Map<String,String> map1 = new HashMap<>();
//⭐HashMap 可以转为线程安全的,下面的 map2 再操作便不会报ConcurrentModificationException
Map<String,String> map2 = Collections.synchronizedMap(new HashMap());
//ConcurrentHashMap 也是线程安全的集合:(写入时复制 COW 计算机程序设计领域的优化策略)
Map<String,String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + "--->" + map);
}, String.valueOf(i + 1)).start();
}
}
Callable
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//如何启动callable
// new Thread(new Runnable()).start();
// new Thread(new FutureTask()).start();
// new Thread(new FutureTask(Callable callable)).start();
//Thread() 只能传 Runnable 参数,FutureTask是Runbable的实现类,FutureTask可以接收Callable类型的参数。
MyThread myThread = new MyThread();
//适配类
FutureTask futureTask = new FutureTask(myThread);
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start();//结果会被缓存。
//get可能会产生阻塞,可使用异步通信解决
Object o = futureTask.get();
System.out.println(o);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call");
return 1024;
}
}CountDownLatch
常用的辅助类
CountDownLatch 递减计数器
public static void main(String[] args) throws InterruptedException {
//计数器初始化为6次。线程调用的次数
CountDownLatch count = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"---Go");
count.countDown();
}).start();
}
count.await();//等待计数器归零,然后向下执行
System.out.println("Over");
}
CyclicBarrier 循环障碍(递增计数)
//集齐七龙珠,召唤神龙
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙");
});
for (int i = 0; i < 7; i++) {
int finalI = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集了"+(finalI+1));
try {
cyclicBarrier.await();//等待计数器达到设置的次数
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
Semaphore 信号量
public static void main(String[] args) {
//信号量:(类比有三个车位,6个车) 可用于资源限流
Semaphore semaphore = new Semaphore(3);
//
for (int i = 0; i < 6; i++) {
new Thread(()->{
try {
semaphore.acquire();//获取信号量
System.out.println(Thread.currentThread().getName()+"进入车位");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//释放信号量
System.out.println(Thread.currentThread().getName()+"离开车位");
}
},i+"").start();
}
}
读写锁
public class ReadWriteLockDemo {
/**
* 独占锁:== 写锁
* 共享锁:== 读锁
*
* ReadWriteLock 读写锁
* 读-读:可以共存
* 读-写:不能共存
* 写-写:不能共存
*/
public static void main(String[] args) {
//MyCache myCache = new MyCache();
MyCacheLock myCache = new MyCacheLock();
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
myCache.write(finalI + "", Thread.currentThread().getName());
}).start();
}
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
myCache.read(finalI + "");
}).start();
}
}
}
class MyCacheLock {
/**
* ReentrantReadWriteLock 读写锁有更高颗粒度的控制
*/
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
/**
* ReentrantLock 普通锁的颗粒度不够,多线程读取数据有问题
*/
//ReentrantLock lock = new ReentrantLock();
private volatile Map<String, String> map = new HashMap<>();
//读的时候所有线程都可以读取
public String read(String key) {
ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "读数据,key = " + key);
return map.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
readLock.unlock();
return null;
}
}
//存的时候只能有一个线程操作
public void write(String key, String value) {
ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "写数据开始");
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写数据结束");
} catch (Exception e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
}
class MyCache {
private volatile Map<String, String> map = new HashMap<>();
public String read(String key) {
System.out.println(Thread.currentThread().getName() + "读数据,key = " + key);
return map.get(key);
}
public void write(String key, String value) {
System.out.println(Thread.currentThread().getName() + "写数据开始");
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写数据结束");
}
}
阻塞队列
操作 | 抛异常 | 有返回值,不抛异常 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add() | offer() | put() | offer(,,) |
移除 | remove() | poll() | take() | poll(,) |
检测队首元素 | Element() | peek() | ||
//add remove element 会抛异常
public static void test1(){
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
queue.add("a");
queue.add("b");
queue.add("c");
//检索队首元素 如果此队列为空,它将抛出异常
//System.out.println(queue.element());
//对满,抛异常 IllegalStateException: Queue full
//queue.add("d");
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
//对空,抛异常
//queue.remove();
}
//offer poll peek 不会抛异常
public static void test2(){
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
queue.offer("a");
queue.offer("b");
queue.offer("c");
//检索队首元素 如果此队列为空,返回null
System.out.println(queue.peek());
//对满,不抛异常 IllegalStateException: Queue full
queue.offer("d");
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
//对空,抛异常
//queue.poll();
}
// put take 阻塞等待
public static void test3() throws InterruptedException {
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
queue.put("a");
queue.put("b");
queue.put("c");
//对满,阻塞等待
//queue.put("d");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
//对空,抛异常
//queue.take();
}
//offer(,,) poll(,) 超时等待
public static void test4() throws InterruptedException {
ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
queue.offer("a");
queue.offer("b");
queue.offer("c");
//对满,超时等待
queue.offer("d",2,TimeUnit.SECONDS);
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
//对空,超时等待
queue.poll(2,TimeUnit.SECONDS);
}
SynchronousQueue 同步队列
没有容量,必须等待元素取出来之后,才能放进去新的元素
/**
* 和其他的BlockingQueue 不一样, SynchronousQueue 不存储元素
* put了一个元素,必须从里面先take取出来,否则不能在put进去值!
* */
public static void main(String[] args) {
SynchronousQueue<String> synchronousQueue = new SynchronousQueue();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " put 1");
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName() + " put 2");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName() + " put 3");
synchronousQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" take "+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" take "+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" take "+synchronousQueue.take());
} catch (Exception e) {
e.printStackTrace();
}
}, "t2").start();
}
/**
t1 put 1
t1 put 2
t2 take 1
t2 take 2
t1 put 3
t2 take 3
*/
线程池
线程池程序运行-》占用系统资源。为了优化资源的使用-》池化技术。
线程池、连接池、内存池、对象池///..... 创建、销毁。十分浪费资源
池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。
线程池的好处
降低资源的消耗、提高响应的速度、方便管理。(线程复用、可以控制最大并发数、线程管理)
线程的三大方法

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
七大参数
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;
}
手动创建线程池
public static void main(String[] args) {
// 最大线程到底该如何定义
// 1、CPU 密集型,几核,就是几,可以保持CPu的效率最高!
// 2、IO 密集型 > 判断你程序中十分耗IO的线程,
// 假设 程序有15个大型任务 ,io十分占用资源,那就至少留15个max线程(一般来两倍)
// 获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());
//手动创建线程成
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3),
Executors.defaultThreadFactory(),
//抛出RejectedExecutionException的被拒绝任务的处理程序。
//new ThreadPoolExecutor.AbortPolicy()
//被拒绝任务的处理程序,直接在execute方法的调用线程中运行被拒绝的任务(main线程执行),除非执行程序已关闭,在这种情况下,任务将被丢弃。
//new ThreadPoolExecutor.CallerRunsPolicy()
//拒绝任务的处理程序,丢弃最旧的未处理请求,然后重试execute ,除非执行程序被关闭,在这种情况下任务被丢弃。
//new ThreadPoolExecutor.DiscardOldestPolicy()
//被拒绝任务的处理程序,它默默地丢弃被拒绝的任务。
new ThreadPoolExecutor.DiscardOldestPolicy()
);
try {
for (int i = 0; i < 5; i++) {
int finalI = i;
poolExecutor.execute(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
printInfo(poolExecutor, finalI + "");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
poolExecutor.shutdown();
}
}
public static void printInfo(ThreadPoolExecutor executor, String name) {
BlockingQueue<Runnable> queue = executor.getQueue();
System.out.println(Thread.currentThread().getName() + "--->"+name+"<----" +
"核心数: " + executor.getCorePoolSize() +
" 活动线程数: " + executor.getActiveCount() +
" 最大线程数: " + executor.getMaximumPoolSize() +
" 任务完成数: " + executor.getCompletedTaskCount() +
" 队列大小: " + (queue.size() + queue.remainingCapacity()) +
" 当前排队线程数: " + queue.size() +
" 队列剩余大小: " + queue.remainingCapacity()
);
}
函数式接口
函数式接口:只包含一个抽象方法的接口,称为函数式接口。
Eg:
@FunctionalInterface public interface Runnable { public abstract void run(); }
Function:函数
public static void main(String[] args) {
Function function = new Function<String, Object>() {
@Override
public Object apply(String o) {
return o;
}
};
//lambda简化
Function function1 = (str)->{return str;};
Function function2 = (str)-> str;
System.out.println(function.apply("str"));
}
Predicate:断言
public static void main(String[] args) {
Predicate predicate = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};
//lambda简化
Predicate<String> predicate1 = str-> str.isEmpty();
System.out.println(predicate.test("s"));
System.out.println(predicate1.test(""));
}
Consumer:消费型接口
/**
* 消费型接口
*/
public static void main(String[] args) {
Consumer<Object> consumer = new Consumer<Object>() {
@Override
public void accept(Object o) {
System.out.println(o);
}
};
Consumer<Object> consumer1 = str-> System.out.println(str);
consumer.accept("ssssss");
}
Supplier:供给型接口
/**
* 供给型接口
*/
public static void main(String[] args) {
Supplier<Object> supplier = new Supplier<Object>() {
@Override
public Object get() {
return "hello";
}
};
Supplier<Object> supplier1 = ()-> "hello";
System.out.println(supplier.get());
}
ForkJoin
ForkJoin 在 JDK 1.7 , 并行执行任务!提高效率。大数据量!工作窃取。
假如我们需要做一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如 A 线程负责处理 A 队列里的任务。但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。
class ForkJoinTask extends RecursiveTask<Long> {
private Long threshold = 100L;
private Long start;
private Long end;
public ForkJoinTask(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long sum = 0;
if ((end - start) < threshold) {
for (long i = start; i <= end; i++) {
sum += i;
}
} else {
long mid = (start + end) / 2;
ForkJoinTask forkJoinTask1 = new ForkJoinTask(start, mid);
ForkJoinTask forkJoinTask2 = new ForkJoinTask(mid + 1, end);
forkJoinTask1.fork();
forkJoinTask2.fork();
Long join1 = forkJoinTask1.join();
Long join2 = forkJoinTask2.join();
sum = join1 + join2;
}
return sum;
}
}
public static Long test() throws ExecutionException, InterruptedException {
ForkJoinPool joinPool = new ForkJoinPool();
ForkJoinTask forkJoinTask = new ForkJoinTask(1L, 100_000_0000L);
java.util.concurrent.ForkJoinTask<Long> submit = joinPool.submit(forkJoinTask);
Long aLong = submit.get();
System.out.println(aLong);
return aLong;
}
本文来自博客园,作者:iyandongsheng,转载请注明原文链接:https://www.cnblogs.com/ieas/p/16672188.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现