Java JUC

JUC简介

在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的 Collection 实现等。

JMM

JMM(Java内存模型Java Memory Model,简称JMM)本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范,定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。
JMM关于同步的规定:
1.线程解锁前,必须把共享变量的值刷新回主内存
2.线程加锁前,必须读取主内存的最新值到自己的工作内存
3.加锁解锁是同一把锁

由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到的线程自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成,其简要访问过程如下图:
在这里插入图片描述

内存可见性 volatile关键字

内存可见性:
 内存可见性(Memory Visibility)是指当某个线程正在使用对象状态而另一个线程在同时修改该状态,需要确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。
 可见性错误是指当读操作与写操作在不同的线程中执行时,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。
可见性错误会导致出现死循环的情况的演示:

public class ApplicationMain {
	public static void main(String[] args) {
		RunnableTest runnableTest = new RunnableTest();
		Thread a=new Thread(runnableTest);
		a.start();
	
		while (true) {
			if (runnableTest.isF()) {
				
				System.out.println("----------dasda");
				break;
			}
		}
	}

}

class RunnableTest implements Runnable{
	
	private boolean flag=false;

	@Override
	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		flag=true;
		System.out.println(flag);
	}

	public boolean isF() {
		return flag;
	}

	public void setF(boolean f) {
		this.flag = f;
	}
	
	
}

在这里插入图片描述
 我们可以通过同步来保证对象被安全地发布。除此之外我们也可以使用一种更加轻量级的 volatile 变量。
volatile 关键字:
Java 提供了一种稍弱的同步机制,即 volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将 volatile 看做一个轻量级的锁,但是又与锁有些不同:
1.对于多线程,不是一种互斥关系(多个线程可以同时操作同一个共享变量)。
2.不能保证变量状态的“原子性操作
在这里插入图片描述

public class ApplicationMain {
	public static void main(String[] args) throws InterruptedException {
		RunnableTest runnableTest = new RunnableTest();
		Thread a=new Thread(runnableTest);
		a.start();

		while (true) {
		

					if (runnableTest.isF()) {

						System.out.println("----------dasda");
						break;
					} 
				
			
		}

		
	}

}

class RunnableTest implements Runnable{
	

	private volatile boolean flag=false;

	@Override
	public void run() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


			
			
					flag = true;
			
		System.out.println(flag);
	}

	public boolean isF() {
		return flag;
	}

	public void setF(boolean f) {
		this.flag = f;
	}
	
	
}

在这里插入图片描述

原子变量 CAS算法

原子变量:
 类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。
 类 AtomicBoolean、AtomicInteger、AtomicLong 和AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。
 AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray 类进一步扩展了原子操作,对这些类型的数组提供了支持。这些类在为其数组元素提供 volatile 访问语义方面也引人注目,这对于普通数组来说是不受支持的。
 核心方法:boolean compareAndSet(expectedValue, updateValue)
 java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
1.AtomicBoolean 、AtomicInteger 、AtomicLong AtomicReference
2.AtomicIntegerArray 、AtomicLongArray
3.AtomicMarkableReference
4.AtomicReferenceArray
5.AtomicStampedReference
CAS 算法:
 CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。
 CAS 是一种无锁的非阻塞算法的实现。
 CAS 包含了 3 个操作数:
1.需要读写的内存值 V
2.进行比较的值 A
3.拟写入的新值 B
 当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值 B 来更新 V 的值,否则不会执行任何操作。
在这里插入图片描述

public class ApplicationMain {
	public static void main(String[] args) throws InterruptedException {
		RunnableTest runnableTest = new RunnableTest();
		Thread a=new Thread(runnableTest);
		a.start();
		Thread a1=new Thread(runnableTest);
		a1.start();


		
	}

}

class RunnableTest implements Runnable{

	AtomicInteger a=new AtomicInteger();
    // int a1=0;
	@Override
	public void run() {

		int andIncrement = a.getAndIncrement();
		// System.out.println(a1++);
		System.out.println(Thread.currentThread().getName()+andIncrement);
	
	}

	
}

同步辅助类

CountDownLatch

 Java 5.0 在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。
 CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
 闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:
1.确保某个计算在其需要的所有资源都被初始化之后才继续执行;
2.确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
3.等待直到某个操作所有参与者都准备就绪再继续执行。

	public static void main(String[] args) {
		
		CountDownLatch countDownLatch=new CountDownLatch(12);
		RunnableTest runnableTest = new RunnableTest(countDownLatch);
		Thread a=new Thread(runnableTest);
		a.start();
		Thread a1=new Thread(runnableTest);
		a1.start();
		for (int i = 0; i < 10; i++) {
			new Thread(runnableTest).start();;
		}
		try {
			// 等待直到其它线程全部执行完毕
			countDownLatch.await();
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName());


		
	}

}

class RunnableTest implements Runnable{
	
	private CountDownLatch countDownLatch;
	

	public RunnableTest(CountDownLatch countDownLatch) {
		super();
		this.countDownLatch = countDownLatch;
	}


	@Override
	public void run() {
	
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName());
	
		countDownLatch.countDown();
	}

	
	
}

CyclicBarrier (栅栏)

一个线程组的线程需要等待所有线程完成任务后再继续执行下一次任务

public class T1 {
	public static void main(String[] args) {
		
		CyclicBarrier cyclicBarrier=new CyclicBarrier(9,new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("fsda");
			}
		});
		RunnableTest runnableTest = new RunnableTest(cyclicBarrier);
		Thread a=new Thread(runnableTest);
		a.start();
		Thread a1=new Thread(runnableTest);
		a1.start();
		for (int i = 0; i < 7; i++) {
			new Thread(runnableTest).start();;
		}
	
		
		System.out.println(Thread.currentThread().getName());


		
	}

}



class RunnableTest implements Runnable{
	
	private CyclicBarrier cyclicBarrier;
	

	public RunnableTest(CyclicBarrier cyclicBarrier) {
		super();
		this.cyclicBarrier = cyclicBarrier;
	}


	@Override
	public void run() {
	
		System.out.println(Thread.currentThread().getName());
		try {
	    	// 线程之间相互等待
			cyclicBarrier.await();
		} catch (InterruptedException | BrokenBarrierException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}

	
	
}

Semaphore(信号灯,可达到熔断限流作用)

Semaphore 是一个计数信号量,必须由获取它的线程释放。

public class T1 {
	public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
		
		Semaphore semaphore =new Semaphore(3);
		RunnableTest runnableTest = new RunnableTest(semaphore);
		Thread a=new Thread(runnableTest);
		a.start();
		Thread a1=new Thread(runnableTest);
		a1.start();
		for (int i = 0; i < 7; i++) {
			new Thread(runnableTest).start();;
		}
	
		
		System.out.println(Thread.currentThread().getName());


		
	}

}



class RunnableTest implements Runnable{
	
	private Semaphore semaphore;
	

	public RunnableTest(Semaphore semaphore) {
		super();
		this.semaphore = semaphore;
	}


	@Override
	public void run() {
		try {
			// 占位置
			semaphore.acquire();
			System.out.println(Thread.currentThread().getName());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
	    	// 释放位置
			semaphore.release();
		}

	
	}

	
	
}

生产者消费者案例(解决虚假唤醒问题)

多线程交互中,必须要防止多线程的虚假唤醒,使用while判断绝对不能用if,以免产生虚假唤醒。
实例一:

public class Test03 {
	public static void main(String[] args) {

		AirConditioner airConditioner = new AirConditioner();
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.increment();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "a").start();
		
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.decrement();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "b").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.increment();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "c").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.decrement();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "d").start();
	}
}

class AirConditioner { // 资源类

	private int number = 0;

	public synchronized void increment() throws InterruptedException {

		while (number != 0) { // 使用while判断绝对不能用if,以免产生虚假唤醒
			this.wait();
		}

		number++;
		System.out.println(Thread.currentThread().getName() + ":" + number);
		this.notifyAll();
	}

	public synchronized void decrement() throws InterruptedException {

		while (number == 0) {
			this.wait();
		}

		number--;
		System.out.println(Thread.currentThread().getName() + ":" + number);
		this.notifyAll();
	}

}

实例一的lock版:

public class Test04 {
	public static void main(String[] args) {

		AirConditioner airConditioner = new AirConditioner();
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.increment();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "a").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.decrement();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "b").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.increment();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "c").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					airConditioner.decrement();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "d").start();
	}
}

class AirConditioner01 { // 资源类

	private int number = 0;
	private Lock lock = new ReentrantLock();
	private Condition condition=lock.newCondition();
	public void increment() throws InterruptedException {

		lock.lock();
		try {
			while (number != 0) { // 使用while判断绝对不能用if,以免产生虚假唤醒
				condition.await();;
			}
			number++;
			System.out.println(Thread.currentThread().getName() + ":" + number);
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}

	public void decrement() throws InterruptedException {

		lock.lock();
		try {
			while (number == 0) {
				condition.await();
			}
			number--;
			System.out.println(Thread.currentThread().getName() + ":" + number);
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}
}

实例二:

/*
 * 生产者和消费者案例
 */
public class ApplicationMain {

	public static void main(String[] args) {
		Clerk clerk = new Clerk();
		
		Productor pro = new Productor(clerk);
		Consumer cus = new Consumer(clerk);
		
		new Thread(pro, "生产者 A").start();
		new Thread(cus, "消费者 B").start();
		
		new Thread(pro, "生产者 C").start();
		new Thread(cus, "消费者 D").start();
	}
	
}

//店员
class Clerk{
	private int product = 0;
	
	//进货
	public synchronized void get(){//循环次数:0
		while(product >= 1){//为了避免虚假唤醒问题,应该总是使用在循环中
			System.out.println("产品已满!");
			
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
			
		}
		
		System.out.println(Thread.currentThread().getName() + " : " + ++product);
		this.notifyAll();
	}
	
	//卖货
	public synchronized void sale(){//product = 0; 循环次数:0
		while(product <= 0){
			System.out.println("缺货!");
			
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
		}
		
		System.out.println(Thread.currentThread().getName() + " : " + --product);
		this.notifyAll();
	}
}

//生产者
class Productor implements Runnable{
	private Clerk clerk;

	public Productor(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
//			try {
//				Thread.sleep(200);
//			} catch (InterruptedException e) {
//			}
//			
			clerk.get();
		}
	}
}

//消费者
class Consumer implements Runnable{
	private Clerk clerk;

	public Consumer(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			clerk.sale();
		}
	}
}

Lock锁中的精确通知访问(Condition)

例子:
多线程之间按顺序调用,A->B->C
AA打印5次,BB打印10次,CC打印15次
…打印十轮。

public class Test04 {
	public static void main(String[] args) {

		ShareResource shareResource = new ShareResource();
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					shareResource.print5();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "a").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					shareResource.print10();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "b").start();

		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				try {
					shareResource.print15();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}, "c").start();


	}
}

class ShareResource { 
	
	private int number=1; // 1:A 2:B 3:C
	private Lock lock=new ReentrantLock();
	private Condition condition1=lock.newCondition();
	private Condition condition2=lock.newCondition();
	private Condition condition3=lock.newCondition();
	
	public void print5() throws InterruptedException {
		lock.lock();
		try {
			while (number != 1) {
				condition1.await();
			}
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
			} 
			number=2;
			condition2.signal();
			
		} finally {
			lock.unlock();
		}
	}
	
	public void print10() throws InterruptedException {
		lock.lock();
		try {
			while (number != 2) {
				condition2.await();
			}
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
			} 
			number=3;
			condition3.signal();
			
		} finally {
			lock.unlock();
		}
	}
	
	public void print15() throws InterruptedException {
		lock.lock();
		try {
			while (number != 3) {
				condition3.await();
			}
			for (int i = 0; i < 15; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
			} 
			number=1;
			condition1.signal();
			
		} finally {
			lock.unlock();
		}
	}
}

并发环境下造成的集合不安全

锁分段机制

 Java 5.0 在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。
 ConcurrentHashMap 同步容器类是Java 5 增加的一个线程安全的哈希表。对与多线程的操作,介于 HashMap 与 Hashtable 之间。内部采用“锁分段”机制替代 Hashtable 的独占锁。进而提高性能。
 此包还提供了设计用于多线程上下文中的 Collection 实现:
ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给
定 collection 时,ConcurrentHashMap 通常优于同步的 HashMap,ConcurrentSkipListMap 通常优于同步的 TreeMap。当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList 优于同步的 ArrayList。

List不安全的演示代码:

public class Test05 {
	public static void main(String[] args) {
		
		List<String> arrayList = new ArrayList<String>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					arrayList.add(UUID.randomUUID().toString().substring(0,8));
					System.out.println(arrayList);
				}
			},String.valueOf(i)).start();
		}
	}
}

解决方案

CopyOnWriteArrayList
copyonwrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行copy,复制出一个新的容器object[ ] newELements,然后新的容器bject[ ] newElements,里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray (newELements);。这样 的好处是可以对copyonwrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以copyonwrite容器也是一种读写分离的思想,读和写不同的容器。

public class Test05 {
	public static void main(String[] args) {
		
		List<String> arrayList = new CopyOnWriteArrayList<String>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					arrayList.add(UUID.randomUUID().toString().substring(0,8));
					System.out.println(arrayList);
				}
			},String.valueOf(i)).start();
		}
	}
}

Set不安全的演示代码

public class Test05 {
	public static void main(String[] args) {
	
		Set<String> hashSet = new HashSet<>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					hashSet.add(UUID.randomUUID().toString().substring(0,8));
					System.out.println(hashSet);
				}
			},String.valueOf(i)).start();
		}
	}
}

解决方案

public class Test05 {
	public static void main(String[] args) {
	
		Set<String> hashSet = new CopyOnWriteArraySet<String>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					hashSet.add(UUID.randomUUID().toString().substring(0,8));
					System.out.println(hashSet);
				}
			},String.valueOf(i)).start();
		}
	}
}

Map不安全的演示代码

public class Test05 {
	public static void main(String[] args) {
		
		Map<String,String> arrayList = new HashMap<>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					arrayList.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
					System.out.println(arrayList);
				}
			},String.valueOf(i)).start();
		}
	}
}

解决方案

public class Test05 {
	public static void main(String[] args) {
		
		Map<String,String> arrayList = new ConcurrentHashMap<>();
		for (int i = 0; i < 30 ;i++) {
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					arrayList.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
					System.out.println(arrayList);
				}
			},String.valueOf(i)).start();
		}
	}
}

ReadWriteLock 读写锁

 ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。写写/读写互斥,读读不互斥。只要没有 writer,读取锁可以由多个 reader 线程同时保持。
 ReadWriteLock 读取操作通常不会改变共享资源,但执行写入操作时,必须独占方式来获取锁。对于读取操作占多数的数据结构。 ReadWriteLock 能提供比独占锁更高的并发性。而对于只读的数据结构,其中包含的不变性可以完全不需要考虑加锁操作。

public class ApplicationMain {

	public static void main(String[] args) {
		
		T a=new T();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				for (int i = 0; i < 10; i++) {
					
					a.getNum();
				}
				
			}
		},"读").start();
		
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				for (int i = 0; i < 2; i++) {
					
					a.setNum(i);
				}
				
			}
		},"写").start();
		
		
		
	}
	
}




class T {
	
	ReadWriteLock lock=new ReentrantReadWriteLock();
	private int num=10;

	public  void getNum() {
		lock.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName()+num);
		} finally {
			lock.readLock().unlock();
		}
	}

	public  void setNum(int num) {
		lock.writeLock().lock();
		try {
			this.num = num;
			System.out.println(Thread.currentThread().getName()+num);
		} finally {
			lock.writeLock().unlock();
		}
	}	
	
}

BlockingQueue 阻塞队列

分类:
在这里插入图片描述
常用方法:
在这里插入图片描述

	public static void main(String[] args) throws InterruptedException{
		
		BlockingQueue<String> a=new ArrayBlockingQueue<>(3);
		a.put("aa");
		a.put("aa");
		a.put("aa");
		boolean offer = a.offer("e", 3, TimeUnit.SECONDS);
		System.out.println(offer);
		
		for (String string : a) {
			System.out.println(string);
		}
		
	}

ForkJoinPool 分支/合并框架 工作窃取

此标题下的内容参考于https://blog.csdn.net/tyrroo/article/details/81390202
 Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。
在这里插入图片描述
1.ForkJoinTask:我们要使用Fork/Join框架,首先需要创建一个ForkJoin任务。该类提供了在任务中执行fork和join的机制。通常情况下我们不需要直接集成ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了两个子类:
a.RecursiveAction:用于没有返回结果的任务
b.RecursiveTask:用于有返回结果的任务
2.ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行:
任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务(工作窃取算法)。
fork方法:用于将新创建的子任务放入当前线程的work queue队列中,Fork/Join框架将根据当前正在并发执行ForkJoinTask任务的ForkJoinWorkerThread线程状态,决定是让这个任务在队列中等待,还是创建一个新的ForkJoinWorkerThread线程运行它,又或者是唤起其它正在等待任务的ForkJoinWorkerThread线程运行它。
Join方法:主要作用是阻塞当前线程并等待获取结果。
注:ForkJoinTask任务是一种能在Fork/Join框架中运行的特定任务,也只有这种类型的任务可以在Fork/Join框架中被拆分运行和合并运行。ForkJoinWorkerThread线程是一种在Fork/Join框架中运行的特性线程,它除了具有普通线程的特性外,最主要的特点是每一个ForkJoinWorkerThread线程都具有一个独立的任务等待队列(work queue),这个任务队列用于存储在本线程中被拆分的若干子任务。
在这里插入图片描述

public class ApplicationMain {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Instant start = Instant.now();
		
		ForkJoinPool pool = new ForkJoinPool();
		
		ForkJoinTask<Long> task = new ForkJoinSumCalculate(0, 4);
		ForkJoinTask<Long> submit = pool.submit(task);
		
		System.out.println(submit.get());
		System.out.println(Thread.currentThread().getName());
		
		Instant end = Instant.now();
		
		System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());
	}
	
	

}

class ForkJoinSumCalculate extends RecursiveTask<Long>{


	private static final long serialVersionUID = -259195479995561737L;
	
	private long start;
	private long end;
	
	private static final long THURSHOLD = 2;  //临界值
	
	public ForkJoinSumCalculate(long start, long end) {
		this.start = start;
		this.end = end;
	}

	@Override
	protected Long compute() {

		long length = end - start;
		
		if(length <= THURSHOLD){
			long sum = 0L;
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			for (long i = start; i <= end; i++) {
				sum += i;
			}
			
			return sum;
		}else{
		

			long middle = (start + end) / 2;
			System.out.println(Thread.currentThread().getName());
			ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle); 
			left.fork(); //进行拆分,调用compute()方法,同时压入线程队列
			
			System.out.println("z2");
			left.join();
			ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle+1, end);
			right.fork(); 
			System.out.println("z3");

			
			return left.join() + right.join();
		}
	}
	
}

jdk8:

		long sum = LongStream.rangeClosed(0L, 10000L).parallel().sum();
		System.out.println(sum);

异步回调

异步体现在:A类通过新起一个线程执行B类的方法,至于B类的方法有没有执行完,暂时不用去等待。

Completablefuture提供了四个静态方法来创建一个异步操作:

①static Completablefuture< Void > runAsync(Runnable runnable)
②public static CompletableFuture< Void > runAsync (Runnable runnable, Executor executor)
③public static < U > Completablefuture< U > supplyAsync(Supplier < U > supplier)
④public static < U > CompletableFuture< U > supplyAsync (Supplier < U > supplier, Executor executor)

①②没有返回值:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) {
		
		CompletableFuture.runAsync(new Runnable() {
			
			@Override
			public void run() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
			}
		}, pool);
		
		System.out.println("main");
		pool.shutdown();

	}

}

③④有返回值:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		CompletableFuture<Integer> result = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				
				return a;
			}
			
		}, pool);
		
		System.out.println("main   "+result.get());
		pool.shutdown();

	}

}

③④完成时的回调方法

在这里插入图片描述
whenComplete可以处理正常和异常的计算结果, exceptionally处理异常情况。
whenComplete和whenCompleteAsync的区别:
whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务。
whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		CompletableFuture<Integer> result = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				
				return a;
			}
			
		}, pool).whenComplete((res,exc)->{
			//可以感知异常但没办法修改返回数据
			System.out.println(Thread.currentThread().getName()+" 结果:"+res +" 异常:"+exc);
		}
		).exceptionally(new Function<Throwable, Integer>() {

			@Override
			public Integer apply(Throwable t) {
				// 感知到异常后返回默认结果
				return 1;
			}
		});
		
		System.out.println("main   "+result.get());
		pool.shutdown();

	}

}
handle方法

和complete一样,可对结果做最后的处理(可处理异常) ,可改变返回值。
在这里插入图片描述

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		CompletableFuture<Integer> result = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				
				return a;
			}
			
		}, pool).handle(new BiFunction<Integer, Throwable, Integer>() {

			@Override
			public Integer apply(Integer res, Throwable u) {
				if (!(u==null)) {
					
					System.out.println(u);
					return 1;
				}

				return res;
			}
		});
		
		System.out.println("main   "+result.get());
		pool.shutdown();

	}

}

线程串行化

在这里插入图片描述
thenApply方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun方法:只要上面的任务执行完成,就开始执行thenRun。

thenApply方法:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		 CompletableFuture<String> thenApply = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("1完成");
				return a;
			}
			
		}, pool).thenApply(new Function<Integer, String>() {

			@Override
			public String apply(Integer t) {
				System.out.println(t);
				return "2完成";
			}
		});
		
		System.out.println("main   "+thenApply.get());
		pool.shutdown();

	}

}

thenAccept方法:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		 CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("完成");
				return a;
			}
			
		}, pool).thenAccept(new Consumer<Integer>() {

			@Override
			public void accept(Integer t) {
				System.out.println(t);
			}
		});
		
		System.out.println("main   ");
		pool.shutdown();

	}

}

thenRun方法:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		 CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;
				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("完成");
				return a;
			}
			
		}, pool).thenRun(new Runnable() {
			// 无法获取上一步的执行结果
			@Override
			public void run() {
				System.out.println("上步已经完成开始执行这个");
			}
		});
		
		System.out.println("main   ");
		pool.shutdown();

	}

}

两任务组合,两任务都完成后再执行第三任务

在这里插入图片描述
在这里插入图片描述
两个任务必须都完成,触发该任务。
thenCombine:组合两个future,获取两个future的返回结果,并返回当前任务的返回值
thenAcceptBoth:组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值。
runAfterBoth:组合两个future,不需要获取future的结果,只需两个future处理完任务后,处理该任务。

runAfterBoth:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;

				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				return a;
			}
			
		}, pool);
		
		 CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(new Supplier<String>() {

			@Override
			public String get() {
			
				return "任务二";
			}
			
		}, pool);
		
		 supplyAsync.runAfterBothAsync(supplyAsync1, new Runnable() {
			
			@Override
			public void run() {
				System.out.println("其他两个已经执行完毕");
			}
		});
		 
		 System.out.println("main");
	
		pool.shutdown();

	}

}

thenAcceptBoth:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;

				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				return a;
			}
			
		}, pool);
		
		 CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(new Supplier<String>() {

			@Override
			public String get() {
			
				return "任务二";
			}
			
		}, pool);
		
		 supplyAsync.thenAcceptBothAsync(supplyAsync1, (t1,t2)->{
			 System.out.println(t1+"-----"+t2);
		 });
		 
		 System.out.println("main");
	
		pool.shutdown();

	}

}

thenCombine:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;

				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				return a;
			}
			
		}, pool);
		
		 CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(new Supplier<String>() {

			@Override
			public String get() {
			
				return "任务二";
			}
			
		}, pool);
		
		 CompletableFuture<Boolean> thenCombineAsync = supplyAsync.thenCombineAsync(supplyAsync1, new BiFunction<String, Integer, Boolean>() {

			@Override
			public Boolean apply(String t, Integer u) {
				System.out.println(t +""+u);
				return true;
			}
		});
		 
		 System.out.println("main"+thenCombineAsync.get());
	
		pool.shutdown();

	}

}

两任务组合,其中一任务完成后就执行第三任务

在这里插入图片描述
在这里插入图片描述
当两个任务中,任意一个future任务完成的时候,执行任务。
applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
runAfterEither:两个任务有一个执行完成,不需要获取future的结果,处理任务,也没有返回值。

acceptEither:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;

				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				return a;
			}
			
		}, pool);
		
		 CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
			
				return 2;
			}
			
		}, pool);
		
		//这两个任务的返回值类型得一样
		 supplyAsync.acceptEitherAsync(supplyAsync1, (t)->{
			 System.out.println(t);
		 });
		 System.out.println("main"+supplyAsync1.get());
	
		pool.shutdown();

	}

}

runAfterEither:

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {

			@Override
			public Integer get() {
				int a=10/2;

				System.out.println(Thread.currentThread().getName()+" 结果:"+a);
				return a;
			}
			
		}, pool);
		
		 CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(new Supplier<String>() {

			@Override
			public String get() {
			
				return "a";
			}
			
		}, pool);
		
	
		 supplyAsync.runAfterEither(supplyAsync1, ()->{
			 System.out.println("s");
		 });
		 System.out.println("main"+supplyAsync1.get());
	
		pool.shutdown();

	}

}

多任务组合

在这里插入图片描述
allof:等待所有任务完成
anyof:只要有一个任务完成

public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		 CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				return "a";
			}
		}, pool);
		 CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				return "b";
			}
		}, pool);
		 CompletableFuture<String> supplyAsync3 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {

				System.out.println("a");
				return "c";
			}
		}, pool);
		 
		 CompletableFuture<Void> allOf = CompletableFuture.allOf(supplyAsync3,supplyAsync2,supplyAsync1);
		allOf.get();
		 
		 System.out.println("main");
	
		pool.shutdown();

	}

}
public class Test {
	
	static ExecutorService pool = Executors.newFixedThreadPool(10);

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		
		 CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				return "a";
			}
		}, pool);
		 CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				return "b";
			}
		}, pool);
		 CompletableFuture<String> supplyAsync3 = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {

				System.out.println("a");
				return "c";
			}
		}, pool);
		 
		 CompletableFuture<Object> anyOf = CompletableFuture.anyOf(supplyAsync3,supplyAsync2,supplyAsync1);
		 // 得到完成任务的返回结果
		 Object object = anyOf.get();
		 
		 System.out.println("main"+"   "+object);
	
		pool.shutdown();

	}

}

其它多线程知识详见javase多线程部分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值