java中线程同步的几种方法
1.同步关键字
Synchronized
2.并发包中锁
Lock
3.object对象等待通知
ObjectMonitor
wait
notify
4.锁对应的条件变量
并发包中锁的条件变量
condition
await
signal
5.并发包中的阻塞队列
BlockingQueue
6.并发包中的原子操作
Atomic
7.volatile
8.final
9.Thread.join
10.CountDownLatch
相当于线程中的方法join方法,不过功能更多。CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。
计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。
11.CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,
所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
12.Semaphore
控制并发线程数的semaphore, Semaphore翻译成字面意思为 信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
如下所示代码中虽然有30个线程在执行,但是只允许10个并发执行,Semaphore(int permits) 接受一个整形数字,表示可用的许可证数量,Semaphore(10)表示允许10个线程获取许可证,也就是并发数为10.
13.Phaser
Phaser类的特点是把多个线程协作执行的任务划分成多个阶段(phase),在每个阶段上都可以有任意个参与者参与。线程可以随时注册并参与到某个阶段的执行中来。当一个阶段中所有的线程都成功完成之后,Phaser类的对象会自动进入下一个阶段,如此循环下去,直到Phaser类的对象中不再包含任何参与者,此时它会自动结束。功能强大,可以替代CountDownLatch和CyclicBarrier。 Phaser的构造器可指定初始的参与者的个数。 (1)register 动态添加参与者 (2)arriveAndAwaitAdvance 完成之后等待其他参与者完成,会阻塞直到Phaser类的对象成功进入下一个阶段 (3)arriveAndDeregister 执行完成之后取消自己的注册,不参与下一个阶段的执行
示例代码如下:

public class PhaserDemo { private final Phaser phaser = new Phaser(1); private final Pattern imageUrlPattern = Pattern.compile("src=['\"]?(.*?(\\.jpg|\\.gif|\\.png))['\"]?[\\s>]+", Pattern.CASE_INSENSITIVE); public void download(URL url, final Path path, Charset charset) throws IOException { if (charset == null) { charset = StandardCharsets.UTF_8; } String content = getContent(url, charset); List<URL> imageUrls = extractImageUrls(content); for (final URL imageUrl : imageUrls) { phaser.register(); new Thread() { public void run() { //等待其他线程创建完成 phaser.arriveAndAwaitAdvance(); //进入图片下载阶段 try { InputStream is = imageUrl.openStream(); Files.copy(is, getSavedPath(path, imageUrl), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { e.printStackTrace(); } finally { phaser.arriveAndDeregister(); } } }.start(); } //等待其他下载线程创建完成 phaser.arriveAndAwaitAdvance(); //等待下载阶段的下载线程执行完成 phaser.arriveAndAwaitAdvance(); //下载完成之后注销自己 phaser.arriveAndDeregister(); } private String getContent(URL url, Charset charset) throws IOException { InputStream is = url.openStream(); return IOUtils.toString(new InputStreamReader(is, charset.name())); } private List<URL> extractImageUrls(String content) { List<URL> result = new ArrayList<URL>(); Matcher matcher = imageUrlPattern.matcher(content); while (matcher.find()) { try { result.add(new URL(matcher.group(1))); } catch (MalformedURLException e) { //忽略 } } return result; } private Path getSavedPath(Path parent, URL url) { String urlString = url.toString(); int index = urlString.lastIndexOf("/"); String fileName = urlString.substring(index + 1); return parent.resolve(fileName); } public static void main(String[] args) throws IOException { URL url = new URL("http://www.baidu.com"); PhaserDemo downloader = new PhaserDemo(); downloader.download(url, Paths.get("imgs"), Charset.forName("GB2312")); } }
14.fork-join
fork/join是java7更新的一个新的轻量级任务执行框架,其主要目的是要更好滴利用底层平台上的多核CPU和多处理器来进行并行处理,解决问题时通常采用分治(divide and conquer)算法或map/reduce算法来进行。
fork操作是把一个大问题划分为若干较小的问题,一般是递归进行。
join操作是把部分解收集并组织起来,得到最终的完整解,也可能是递归进行的。
如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行,减少了线程等待时间,提高了性能。
ForkJoinTask的子类:RecursiveTask(可返回结果)与RecursiveAction。
ForkJoinPool实现了ExecutorService接口。
示例代码如下:

public class ForkJoinDemo { private static final int RANGE_LENGTH = 2000; private final ForkJoinPool forkJoinPool = new ForkJoinPool(); private static class MaxValueTask extends RecursiveTask<Long> { private final long[] array; private final int start; private final int end; MaxValueTask(long[] array, int start, int end) { this.array = array; this.start = start; this.end = end; } protected Long compute() { long max = Long.MIN_VALUE; if (end - start <= RANGE_LENGTH) { for (int i = start; i < end; i++) { if (array[i] > max) { max = array[i]; } } } else { int mid = (start + end) / 2; MaxValueTask lowTask = new MaxValueTask(array, start, mid); MaxValueTask highTask = new MaxValueTask(array, mid, end); lowTask.fork(); highTask.fork(); max = Math.max(max, lowTask.join()); max = Math.max(max, highTask.join()); } return max; } } public void calculate(long[] array) { MaxValueTask task = new MaxValueTask(array, 0, array.length); Long result = forkJoinPool.invoke(task); System.out.println(result); } public void calculateNormal(long[] array) { long max = Long.MIN_VALUE; for (int i = 0, n = array.length; i < n; i++) { if (array[i] > max) { max = array[i]; } } System.out.println(max); } public static void main(String[] args) { Random random = new Random(); int size = Integer.MAX_VALUE / 256; long[] array = new long[size]; for (int i = 0; i < size; i++) { array[i] = random.nextLong(); } ForkJoinDemo mv = new ForkJoinDemo(); long startTime = System.currentTimeMillis(); mv.calculate(array); long midTime = System.currentTimeMillis(); System.out.println(midTime - startTime); mv.calculateNormal(array); long endTime = System.currentTimeMillis(); System.out.println(endTime - midTime); } }
15.parrelStream
Java8并行流ParallelStream和Stream的区别就是支持并行执行,提高程序运行效率。但是如果使用不当可能会发生线程安全的问题。Demo如下:

public static void concurrentFun() { List<Integer> listOfIntegers = new ArrayList<>(); for (int i = 0; i <100; i++) { listOfIntegers.add(i); } List<Integer> parallelStorage = new ArrayList<>() ; listOfIntegers .parallelStream() .filter(i->i%2==0) .forEach(i->parallelStorage.add(i)); System.out.println(); parallelStorage .stream() .forEachOrdered(e -> System.out.print(e + " ")); System.out.println(); System.out.println("Sleep 5 sec"); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } parallelStorage .stream() .forEachOrdered(e -> System.out.print(e + " ")); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY