首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一个多线程异步执行面试题的多种解决方法

一个多线程异步执行面试题的多种解决方法

作者头像
冬天里的懒猫
发布于 2021-08-31 08:00:48
发布于 2021-08-31 08:00:48
86300
代码可运行
举报
运行总次数:0
代码可运行

文章目录

1.问题

题目如下: 在 main 函数启动一个新线程,运行一个方法,拿到这个方法的返回值后,退出主线程?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Homework03 {

	public static void main(String[] args) {
		long start = System.currentTimeMillis();

		// 在这里创建一个线程或线程池,
		// 异步执行 下面方法
		int result = sum();

		System.out.println("异步计算结果:"+result);
		System.out.println("计算耗时:"+(System.currentTimeMillis() - start) +"  ms");
		
	}
	
	private static int sum() {
		return fibo(36);
	}
	
	private static int fibo(int a) {
		if(a<2){
			return 1;
		}
		return fibo(a-1) + fibo(a-2);
	}
	
}

题目的实际要求是,在main线程中,启动一个线程或者线程池,来执行一个斐波那契数列的求和运算,之后在计算完毕之后,将计算结果返回到主线程。 对于这个问题,实际上就是两个线程,main线程和计算线程之间的通讯问题。主线程在启动计算线程之后,需要进入等待或者阻塞状态,直到等待的变量状态改变,或者被阻塞的任务执行完毕,之后再运行获取结果的方法,拿到计算结果。 大致可以分为 共享内存、join、同步工具等多种解决方案。

2.解决方法

2.1 线程的Join方法

线程的join方法本身就是jvm实现的,让当前线程进行阻塞,等待被执行线程结束之后再执行的方法。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun02 {

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();

		sumThread.start();
		sumThread.join();
		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			result = sum();
		}
	}

}

2.2 共享volatile变量

可以让两个线程共享一个volatile的变量,计算线程在计算完成之后,更新这个volatile变量的状态为ture,那么main线程只需要在计算线程启动之后,不断轮询监控该变量的状态即可。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun03 {

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();

		sumThread.start();

		while (!sumThread.isSuccess()) {
			TimeUnit.MILLISECONDS.sleep(1);
		}

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;
		private volatile boolean success = false;

		public boolean isSuccess() {
			return success;
		}

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			result = sum();
			success = true;
		}
	}

}

2.3 synchronized锁

synchronized可以实现这个需求,但是需要一个前提,就是让计算线程先拿到锁,这之后main线程被synchronized阻塞。直到计算线程执行完毕,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun04 {

	private static final Object lock = new Object();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		
		TimeUnit.MILLISECONDS.sleep(1);
		synchronized (lock) {

		}
		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			synchronized (lock) {
				result = sum();
			}
		}
	}
}

2.4 wait+notify/notifyAll

可以利用object对象的wait+notify/notifyAll方法来实现。在启动完计算线程之后将主线程wait,之后在计算线程中,执行完毕之后,调用notify/notifyAll方法来唤醒主线程继续执行。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun05 {

	private static final Object lock = new Object();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();

		sumThread.start();
		synchronized (lock) {
			lock.wait();
		}

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			synchronized (lock) {
				result = sum();
				lock.notifyAll();
			}
		}
	}
}

2.5 park/unpark

同理,也可以利用同步工具中的lockSupport的park/unpark方法来实现。在主线程启动计算线程之后执行park,之后再在计算线程执行完毕之后,调用主线程的unpark方法。diamagnetic如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun07 {
	
	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.setMainThread(Thread.currentThread());
		sumThread.start();
		LockSupport.park();

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Thread mainThread;

		private Integer result;

		public Integer getResult() {
			return result;
		}

		public Thread getMainThread() {
			return mainThread;
		}

		public void setMainThread(Thread mainThread) {
			this.mainThread = mainThread;
		}

		@Override
		public void run() {
			result = sum();
			LockSupport.unpark(getMainThread());
		}
	}

}

2.6 ReentrantLock可重入锁

同样,参考synchronized,也可以通过可重入锁ReentrantLock,但是需要先让计算线程抢到锁,之后main线程会被阻塞直到计算线程执行完毕。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun08 {

	private static final ReentrantLock lock = new ReentrantLock(true);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();

		TimeUnit.MILLISECONDS.sleep(1);
		lock.lock();
		try {
			System.out.println("***");
		} finally {
			lock.unlock();
		}

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			lock.lock();
			try {
				result = sum();
			} finally {
				lock.unlock();
			}
		}
	}

}

2.7 ReentrantLock配合Condation

当然,既然使用了ReentrantLock,那么还有一种与wait/notify等价的方法,就是结合Condation,通过Condation的await和signalAll/signal方法。 在启用了计算线程之后,通过Condation的await方法阻塞,待计算线程执行完毕再执行signal方法。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun09 {

	private static final ReentrantLock lock = new ReentrantLock(true);
	private static final Condition c1 = lock.newCondition();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();

		lock.lock();
		try {
			c1.await();
		} finally {
			lock.unlock();
		}

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			lock.lock();
			try {
				result = sum();
				c1.signalAll();
			} finally {
				lock.unlock();
			}
		}
	}
}

2.8 CountDownLatch

在java的并发包中,有很多同步的工具可以来实现这个场景,定义一个CountDownLatch,需要倒计时的线程为1,当main线程启动线程之后,让CountDownLatch执行await方法,计算线程在计算完毕之后,执行countdown方法。mian线程则会继续执行。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun06 {

	private static final CountDownLatch latch = new CountDownLatch(1);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();

		sumThread.start();
		latch.await();

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			result = sum();
			latch.countDown();
		}
	}

}

2.9 CyclicBarrier

同理,CyclicBarrier也可以在这个场景使用。主线程启动计算线程之后,执行await,之后计算线程执行完之后,也执行await,这个内存屏障设为2,则正好解除屏障,继续执行。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun10 {

	private static final CyclicBarrier barrier = new CyclicBarrier(2);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		barrier.await();

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {
		
		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			try {
				result = sum();
				barrier.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
	}
}

2.10 Semaphore

Semaphore也能很好的实现,Semaphore初始为0,在主线程中执行acquire,自然会被阻塞,等到计算线程执行完毕,执行release。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun11 {

	private static final Semaphore semaphore = new Semaphore(0);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		semaphore.acquire();

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {
		
		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			try {
				result = sum();
				semaphore.release();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

2.11 Phaser

Phaser如果要实现这个场景,则设置Phaser为2,在主线程和计算线程中都执行arriveAndAwaitAdvance。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun12 {

	private static final Phaser phaser = new Phaser(2);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		phaser.arriveAndAwaitAdvance();

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			try {
				result = sum();
				phaser.arriveAndAwaitAdvance();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

2.12 Exchanger

Exchanger是最适合两个线程通信的工具。尤其是交替执行的两个线程。主线程和计算线程都通过exchange方法,同时被阻塞住,然后交换数据。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun13 {

	private static final Exchanger<Integer> exchanger = new Exchanger<>();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		Integer result = exchanger.exchange(0);

		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		@Override
		public void run() {
			try {
				int result = sum();
				exchanger.exchange(result);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

2.13 BlockingQueue

BlockingQueue的take方法,也是有阻塞效果的,那么对于这一类的Queue,或者List,可以在主线程启动起算线程之后,通过take方法进行阻塞。而一旦计算线程执行完毕,将数据加入到queue,则阻塞被解除。采用ArrayBlockingQueue实现。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun14 {

	private static final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1);

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		Integer result = queue.take();

		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		@Override
		public void run() {
			try {
				int result = sum();
				queue.add(result);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

2.14 SynchronousQueue

SynchronousQueue是一个特殊的Queue,只能允许1个长度,本质上与BlockingQueue的原理一致。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun15 {

	private static final SynchronousQueue<Integer> queue = new SynchronousQueue<>();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		Integer result = queue.take();

		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {


		@Override
		public void run() {
			try {
				int result = sum();
				queue.add(result);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

2.15 List/Set非阻塞集合

在使用了阻塞的集合实现之后,同样,非阻塞的集合也能实现,这个与通过volatile共享变量类似。需要主线程轮询集合的状态,是否isEmpty。如下采用ArrayList实现。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun16 {

	private static final ArrayList<Integer> list = new ArrayList<>();

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		while (list.isEmpty()) {
			TimeUnit.MILLISECONDS.sleep(1);
		}
		Integer result = list.get(0);
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {
		
		@Override
		public void run() {
			try {
				int result = sum();
				list.add(result);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

2.16 Thread.isAlive

由于本题的特殊性,也可以不用第三变量,直接判断计算线程的状态,isAlive方法,在isAlive方法中轮询sleep,待计算线程执行完毕。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun19 {

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		SumThread sumThread = new SumThread();
		sumThread.start();
		do {
			TimeUnit.MILLISECONDS.sleep(1);
		} while (sumThread.isAlive());

		int result = sumThread.getResult();
		System.out.println("异步计算结果:" + result);
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread extends Thread {

		private Integer result;

		public Integer getResult() {
			return result;
		}

		@Override
		public void run() {
			result = sum();
		}
	}
}

2.17 Callable

由于Runnable是没有返回值的,那么java再解决这个问题的时候引入了Callable,我们也可以利用Callable来实现。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun01 {

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();

		ExecutorService executorService = Executors.newSingleThreadExecutor();

		Callable<Integer> task = new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				return sum();
			}
		};
		Future<Integer> future = executorService.submit(task);
		System.out.println("异步计算结果:" + future.get());
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
		executorService.shutdown();

	}

	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}
}

2.18 FutureTask

当然,还可以通过FutureTask来拿到线程异步执行的返回结果。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun17 {


	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		ExecutorService service = Executors.newCachedThreadPool();

		SumThread sumThread = new SumThread();
		FutureTask<Integer> futureTask = new FutureTask<>(sumThread);
		service.submit(futureTask);
		service.shutdown();
		System.out.println("异步计算结果:" + futureTask.get());
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread implements Callable<Integer> {

		@Override
		public Integer call() throws Exception {
			return sum();
		}
	}
}

2.19 CompleteFuture

jvm1.8中引入了CompleteFuture,也能在这个场景中来使用。 代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncRun18 {
	
	private static int sum() {
		return fibo(36);
	}

	private static int fibo(int a) {
		if (a < 2) {
			return 1;
		}
		return fibo(a - 1) + fibo(a - 2);
	}

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		ExecutorService service = Executors.newCachedThreadPool();

		CompletableFuture<Integer> future = new CompletableFuture<>();
		SumThread sumThread = new SumThread(future);
		service.submit(sumThread);
		service.shutdown();

		System.out.println("异步计算结果:" + future.get());
		System.out.println("计算耗时:" + (System.currentTimeMillis() - start) + "  ms");
	}

	static class SumThread implements Runnable {

		private CompletableFuture<Integer> future;

		public SumThread(CompletableFuture<Integer> future) {
			this.future = future;
		}

		@Override
		public void run() {
			future.complete(sum());
		}
	}
}

3.总结

本文共列举了19种方法来实现异步执行线程并得到其执行结果的需求。这都是java线程通信的常用方法,每种方法的使用大同小异。采用轮询是最不可取的方法,这样会导致主线程浪费CPU资源,增加服务器不必要的开销。 类似于茴香豆的茴有几种写法,多少种并不是关键,我们需要的是掌握这每一种线程通信方法的使用场景,在业务开发中灵活应用。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
阿里的面试题带你认识ForkJoinPool
随着在硬件上多核处理器的发展和广泛使用,并发编程成为程序员必须掌握的一门技术,在面试中也经常考查面试者并发相关的知识。
狼王编程
2021/06/01
5370
阿里的面试题带你认识ForkJoinPool
采用线程池进行异步任务处理
被@Async修饰的方法叫做异步方法,这些异步方法会在新的线程中进行处理,不影响主线程的顺序执行。
春哥大魔王
2018/07/23
3.3K0
springboot创建及使用多线程的几种方式
在数据处理中,多线程用到的场景很多,在满足计算机CPU处理能力的情况下,使用多线程可以明显提高程序运行效率,缩短大数据处理的能力。作为java程序开发,离不开spring,那么在spring中怎么创建多线程并将注册到spring的类在多线程中使用呢?我自己总结了一下,可以有两种方式,使用线程池和spring自带多线程注解使用。 使用线程池 我一般使用固定线程数量的线程池,假如数据量很大,我会将数据放到一个大集合中,然后按照一定的比例分配数目,同时我自己写了一个分页类,线程的数量可以根据分页类来自动调整。看代
神秘的寇先森
2018/06/19
8.7K1
Java 实现多线程的n种方法
在现代编程中,多线程是一项关键技术,它使得程序能够同时执行多个任务,提高了系统的效率和性能。在Java中,有多种方法可以实现多线程,每种方法都有其独特的应用场景和优缺点。本文将详细介绍几种常见的Java多线程实现方法,包括基础的Thread类、Runnable接口、高级的线程池、并发工具类、异步编程以及新的并发特性,帮助你深入理解多线程的不同实现方式。
繁依Fanyi
2024/11/22
4710
Java多线程中join方法的理解
许多同学刚开始学Java 多线程时可能不会关主Join 这个动作,因为不知道它是用来做什么的,而当需要用到类似的场景时却有可能会说Java 没有提供这种功能。 当我们将一个大任务划分为多个小任务,多个小任务由多个线程去完成时,显然它们完成的先后顺序不可能完全一致。在程序中希望各个线程执行完成后,将它们的计算结果最终合并在一起,换句话说,要等待多个线程将子任务执行完成后,才能进行合并结果的操作。 这时就可以选择使用Join 了,Join 可以帮助我们轻松地搞定这个问题,否则就需要用个循环去不断判定每个线程的
JavaEdge
2018/05/16
1.8K0
JUC并发—13.Future模式和异步编程简介
Callable接口需要与Future和ExecutorService结合使用:通过ExecutorService的submit()方法提交一个实现Callable接口的任务,然后ExecutorService的submit()方法会返回一个实现Future接口的对象,接着调用Future接口的get()方法就可以获取异步任务的结果。
东阳马生架构
2025/05/06
1290
Java多线程最佳实践指南
最近正值秋招旺季,面试免不了问一些多线程的问题,而在Java多线程编程中,为了确保程序的稳定性和性能,我们需要遵循一系列的最佳实践。本文将介绍这些最佳实践,并提供代码示例来帮助理解。
灬沙师弟
2024/10/10
3510
Java多线程最佳实践指南
java---多线程[重点(下)]
第三种创建线程的方式,使用Callable创建的线程可以有一个返回值。Interface Callable<V>它是一个接口和Runnable一样。void run() 这方法是一个无返回值,无参数的方法。Callable 提供了一个call()返回可以返回一个值,这个值的类型由Callable<V>泛型决定。
用户10787181
2023/10/17
3680
java---多线程[重点(下)]
【JUC】009-ForkJoin分支合并、异步回调、JMM、Volatile关键字、指令重排
Java 7开始引入了一种新的Fork/Join线程池,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行;
訾博ZiBo
2025/01/06
1420
【JUC】009-ForkJoin分支合并、异步回调、JMM、Volatile关键字、指令重排
了解多线程以及如何进行并发编程?
硬件层面软件层面并发和并行JAVA中的线程线程的基础源码分析线程的启动线程的中断异步并发异步 Future异步Callback异步编排 CompletableFuture小结更多
架构探险之道
2020/07/07
8530
了解多线程以及如何进行并发编程?
java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?
java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求:
路人甲Java
2019/12/10
6410
Java多线程JUC
1. volatile 关键字 多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从主存取到数据,然后放到自己的缓冲区中,在做完修改之后放回主存。这样每一个线程之间的变量是不可见的。造成读到的数据可能始终就是错误的,因此有一个关键字可以使得这个共享变量称为透明的。就好像所有的操作就直接是在内存中操作一样,因为他一直不停的去同步主存的数据。 2.原子性 i++ 这个运算,其实在底层低用的就是临时变量的方式,这样的话虽然是一个表达式,但
lwen
2018/04/17
6280
Java多任务编排技术
JDK 5新增Future接口,用于处理异步计算结果。虽然Future提供异步执行任务能力,但是获取结果很不方便,要么通过Future#get阻塞调用线程,或者通过轮询 Future#isDone判断任务是否结束,再获取结果。
科技新语
2025/07/31
2000
Java多任务编排技术
多线程进阶--JUC并发编程
https://blog.csdn.net/weixin_44502509/article/details/106872957
hhss
2021/02/12
6900
多线程进阶--JUC并发编程
CompletableFuture 异步多线程,那叫一个优雅
虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,我们必须使用Future.get()的方式阻塞调用线程,或者使用轮询方式判断 Future.isDone 任务是否结束,再获取结果。
程序员大彬
2023/03/01
1.9K0
CompletableFuture 异步多线程,那叫一个优雅
京东这道面试题你会吗?
现在呢,我们有三个接口,就叫他A,B,C吧,这三个接口都是查询某个人征信信息的,必须同时返回true,我们才认为这个人的征信合格,如果其中某一个返回false的话,就表明这个人的征信不合格,如果是你,你会怎么设计怎么写这个代码呢?
java小杰要加油
2021/05/13
3340
京东这道面试题你会吗?
JUC-Java多线程Future,CompletableFuture
2个并:并发(concurrent)在同一实体上的多个事件,在一台处理器上“同时处理多个任务”,同一时刻,其实是只有一个时间在发生
鱼找水需要时间
2023/02/16
5080
JUC-Java多线程Future,CompletableFuture
Java并发编程系列-(2) 线程的并发工具类
JDK 7中引入了fork-join框架,专门来解决计算密集型的任务。可以将一个大任务,拆分成若干个小任务,如下图所示:
码老思
2023/10/19
2840
Java并发编程系列-(2) 线程的并发工具类
SpringBoot实现多线程
代码地址:https://github.com/Snowstorm0/learn-async
代码的路
2022/08/23
1.9K0
SpringBoot实现多线程
JUC系列(七) ForkJion任务拆分与异步回调
常见的两种创建线程的方式。一种是直接继承Thread,另外一种就是实现Runnable接口。
冷环渊
2022/12/03
4100
JUC系列(七) ForkJion任务拆分与异步回调
推荐阅读
相关推荐
阿里的面试题带你认识ForkJoinPool
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
一站式MCP教程库,解锁AI应用新玩法
涵盖代码开发、场景应用、自动测试全流程,助你从零构建专属AI助手
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档