Java与Go:并发

news2024/11/17 7:45:32

在此之前,我们先要明白什么是并发?为什么要并发编程?

在计算机中,同一时刻,只能有一条指令,在一个CPU上执行 后面的指令必须等到前面指令执行完才能执行,就是串行。在早年CPU核心数还少的时候倒是没什么。但是现如今,CPU性能(核心数和频率)已经不同往昔,为了充分利用CPU性能,我们引入并发。就好比银行只有5个窗口,有5个人要办事,就可以一起处理,第六个人到来才需要排队。

Java如何进行并发编程

在 Java 中进行并发编程可以利用语言和库提供的特性,如线程、线程池、同步机制等。Java 为并发编程提供了许多有用的工具和库,包括基本的 Thread 类、并发集合、锁、条件变量等。在 Java 7 及以上版本中,java.util.concurrent 包还提供了更高层次的并发编程工具,包括线程池、并发队列、异步任务(FutureCompletableFuture)等。

1. 开辟新线程

  • Thread:Java 提供了 Thread 类来创建和管理线程。你可以通过继承 Thread 类或实现 Runnable 接口来定义线程。
public class MyThread extends Thread {
    @Override
    public void run() {
        // 在这个方法中定义线程要执行的任务
        System.out.println("Thread is running");
    }

    public static void main(String[] args) {
        // 创建 MyThread 类的实例
        MyThread myThread = new MyThread();
        // 启动线程
        myThread.start();
    }
}

  • Runnable 接口:通过实现 Runnable 接口,并将其传递给 Thread 类的构造函数,来定义线程的执行逻辑。
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 在这个方法中定义线程要执行的任务
        System.out.println("Runnable is running");
    }

    public static void main(String[] args) {
        // 创建 MyRunnable 类的实例
        MyRunnable myRunnable = new MyRunnable();
        // 将 Runnable 对象传递给 Thread 构造函数
        Thread thread = new Thread(myRunnable);
        // 启动线程
        thread.start();
    }
}

2. 同步与锁

  • synchronized 关键字:用于在方法或代码块上加锁,确保在同一时间只有一个线程可以执行受保护的代码。
  • Lock 接口:提供了 synchronized 的替代方法,更灵活的锁定机制。
  • ReadWriteLock:提供了读写锁,用于优化读多写少的场景。

3. 线程池

  • ExecutorService:用于管理线程池,可以通过 Executors 类提供的方法来创建不同类型的线程池。
  • ScheduledExecutorService:用于安排定时或周期性的任务执行。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ConcurrencyDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 提交任务给线程池
        Future<?> future1 = executor.submit(() -> {
            System.out.println("任务 1 开始");
            // 执行任务逻辑
            System.out.println("任务 1 结束");
        });
        
        Future<?> future2 = executor.submit(() -> {
            System.out.println("任务 2 开始");
            // 执行任务逻辑
            System.out.println("任务 2 结束");
        });

        // 等待任务执行完成
        try {
            future1.get(); // 阻塞直到任务 1 完成
            future2.get(); // 阻塞直到任务 2 完成
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executor.shutdown();
    }
}

创建了一个固定大小为 3 的线程池,然后提交了两个任务,并等待它们执行完毕。最后关闭线程池。

4. 并发集合

  • java.util.concurrent 包中的并发集合:例如 ConcurrentHashMapCopyOnWriteArrayListConcurrentLinkedQueue 等,适合在多线程环境下使用。

5. 异步任务与回调

  • Future 接口:代表异步计算的结果。可以通过 ExecutorService 提供的方法提交任务,得到 Future 对象。
  • CompletableFuture:更高级的异步任务工具,提供链式回调、组合和异常处理等功能。

6. 其他并发工具

  • CountDownLatch:用于线程同步,让线程等待直到某些操作完成。
  • CyclicBarrier:一个同步点,允许多个线程等待彼此到达一个状态。
  • Semaphore:用于控制资源的访问数量。

Go语言怎么并发

Go 语言以其强大的并发编程特性而闻名。Go 语言提供了一些基本概念和机制来处理并发,包括 goroutines、channels 和 select 语句。这些工具使得 Go 在处理并发任务时非常高效且易于编写。

1. Goroutine

  • Goroutine 是 Go 语言中的轻量级线程。通过使用 go 关键字,可以在后台启动一个新的 goroutine 来执行任务。
  • Goroutine 是非常轻量级的,可以同时启动大量 goroutine,而不会对系统资源产生很大的负担。
package main

import (
    "fmt"
)

func sayHello() {
    fmt.Println("Hello!")
}

func main() {
    go sayHello() // 启动一个新的 goroutine 执行 sayHello 函数

    fmt.Println("Main goroutine")
}

2. Channels

  • Channels 是 Go 语言中用于 goroutine 之间通信的工具。通过 channels,可以在不同的 goroutine 之间传递数据。
  • 可以使用 make 函数创建 channels,并通过 <- 运算符发送和接收数据。
package main

import (
    "fmt"
)

func producer(ch chan int) {
    for i := 0; i < 5; i++ {
        ch <- i // 发送数据到 channel
        fmt.Printf("Produced: %d\n", i)
    }
    close(ch) // 关闭 channel
}

func consumer(ch chan int) {
    for value := range ch { // 从 channel 接收数据
        fmt.Printf("Consumed: %d\n", value)
    }
}

func main() {
    ch := make(chan int) // 创建一个整型 channel

    go producer(ch) // 启动生产者 goroutine
    go consumer(ch) // 启动消费者 goroutine

    // 让主程序等待 goroutine 结束
    // 可以使用 time.Sleep() 或 wait group 来实现
}

3. Select 语句

  • select 语句用于在多个 channel 上等待,并选择其中一个准备好的 channel 进行通信。
  • select 语句类似于 switch 语句,但它是针对 channels 的。
package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        time.Sleep(2 * time.Second)
        ch1 <- 1
    }()

    go func() {
        time.Sleep(1 * time.Second)
        ch2 <- 2
    }()

    select {
        case value := <-ch1:
            fmt.Printf("Received %d from ch1\n", value)
        case value := <-ch2:
            fmt.Printf("Received %d from ch2\n", value)
    }
}

select 语句等待两个 channel 之一发送数据,然后接收数据并执行相应的分支。

这些是 Go 语言中并发编程的基本概念和用法。通过组合这些特性,Go 语言可以处理复杂的并发任务。

Java的虚拟线程

Java 21 中引入了 虚拟线程(Virtual Threads) ,它是一种新的线程实现,旨在提高并发应用程序的性能和可扩展性。虚拟线程与传统线程不同,它们是一种轻量级的线程实现,可以在 Java 虚拟机(JVM)上更有效地处理大量并发任务。

以下是虚拟线程的主要特点和优势:

1. 轻量级

  • 虚拟线程是轻量级的,创建和销毁的开销很小,因此可以在应用程序中创建大量虚拟线程。
  • 与传统线程相比,虚拟线程的资源占用较小,这使得在大量并发任务的场景下更加高效。

2. 阻塞友好

  • 虚拟线程可以友好地阻塞在 I/O 操作或其他同步操作上,而不会影响其他虚拟线程的执行。
  • JVM 可以将阻塞的虚拟线程切换到其他可运行的虚拟线程,保持高效的并发执行。

3. 无缝集成

  • 虚拟线程与现有的 Java 代码无缝集成,这意味着开发者可以在现有的代码基础上直接使用虚拟线程。
  • 开发者可以继续使用现有的并发 API,如 ThreadExecutorService 等,只需将其替换为虚拟线程的实现即可。

4. 简单的编程模型

  • 虚拟线程提供了一个更简单的编程模型,因为开发者可以像使用普通线程一样使用虚拟线程。
  • 开发者可以更专注于业务逻辑,而不必担心底层线程管理的复杂性。

5. 高性能

  • 虚拟线程的调度和执行更高效,可以充分利用多核 CPU 的优势。
  • 对于需要处理大量并发任务的应用程序,虚拟线程可以显著提高性能。

使用示例:

使用虚拟线程非常简单,只需在 Thread 类的实例化中指定 Thread.ofVirtual() 作为工厂方法即可:

public class VirtualThreadExample {
    public static void main(String[] args) {
        Runnable task = () -> {
            System.out.println("Virtual thread is running");
        };

        // 创建一个虚拟线程
        Thread virtualThread = Thread.ofVirtual().start(task);

        // 等待虚拟线程执行完毕
        try {
            virtualThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们使用 Thread.ofVirtual() 创建了一个虚拟线程,并启动它来执行指定的任务。与传统线程的使用类似,但虚拟线程在性能和资源效率方面有更大的优势。

虚拟线程是 Java 21 的一个重要特性,为开发者提供了处理大量并发任务的强大工具。

往期推荐

Java与Go:字符串转IP地址

Java与Go:文件IO

Java vs. Go:时间函数

Java与Go:字符串方法

Java与Go:方法和接口

Java与Go:引用和指针

Java与Go:对象

Java与Go:Map

Java 与 Go:可变数组

Java 与 Go:数组

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

求矩阵对角线元素之和(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int sum 0;int a[3][3] { 0 };//获取数组a的值&#xff1b;printf(&qu…

pandas学习笔记12

缺失数据处理 其实在很多时候&#xff0c;人们往往不愿意过多透露自己的信息。假如您正在对用户的产品体验做调查&#xff0c;在这个过程中您会发现&#xff0c;一些用户很乐意分享自己使用产品的体验&#xff0c;但他是不愿意透露自己的姓名和联系方式&#xff1b; 还有一些用…

【论文阅读】Learning Texture Transformer Network for Image Super-Resolution

Learning Texture Transformer Network for Image Super-Resolution 论文地址Abstract1. 简介2.相关工作2.1单图像超分辨率2.2 Reference-based Image Super-Resolution 3. 方法3.1. Texture TransformerLearnable Texture Extractor 可学习的纹理提取器。Relevance Embedding.…

Linux的socket详解

一、本机直接的进程通信方式 管道&#xff08;Pipes&#xff09;&#xff1a; 匿名管道&#xff08;Anonymous pipes&#xff09;&#xff1a;通常用于父子进程间的通信&#xff0c;它是单向的。命名管道&#xff08;Named pipes&#xff0c;也称FIFO&#xff09;&#xff1a;允…

【Linux】进程控制 之 进程创建 进程终止 进程等待 进程替换

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

H.265 与 H.264 的主要区别

H.265 与 H.264 的主要区别 H.265 与 H.264 的主要区别各模块技术差异汇总宏块划分帧内预测模式帧间预测模式去块滤波ALF自适应环路滤波采样点自适应偏移&#xff08;Sample Adaptive Offset&#xff09;滤波并行化设计TileEntropy sliceDependent SliceWPP&#xff08;Wavefro…

docker部署nginx并实现https

文章目录 docker部署nginx并实现https1、服务器环境2、安装docker3、准备证书4、准备nginx配置文件和dockerfile文件5、创建nginx镜像与容器6、验证访问 docker部署nginx并实现https 1、服务器环境 [rootliuyanfen12 ~]#systemctl stop firewalld [rootliuyanfen12 ~]#setenf…

HTML/CSS1

1.前置说明 请点这里 2.img元素 格式&#xff1a; <img src"图片地址" alt"占位文字" width"图片宽度" height"图片高度">其中alt是当图片加载失败时显示的文字 而且不同内核的浏览器显示出来的占位文字的效果也是不尽相同的…

Django之单文件上传(以图片为例)

一&#xff0c;创建项目 初始化&#xff0c;数据迁移&#xff0c;创建superuser&#xff0c;创建app等 二&#xff0c;配置settings.py 1&#xff0c;配置数据库&#xff08;本作者使用的mysql&#xff09;&#xff0c;以前文章有提到 2&#xff0c;配置静态文件存放路径 STAT…

论文笔记ColdDTA:利用数据增强和基于注意力的特征融合进行药物靶标结合亲和力预测

ColdDTA发表在Computers in Biology and Medicine 的一篇一区文章 突出 • 数据增强和基于注意力的特征融合用于药物靶点结合亲和力预测。 • 与其他方法相比&#xff0c;它在 Davis、KIBA 和 BindingDB 数据集上显示出竞争性能。 • 可视化模型权重可以获得可解释的见解。 …

安卓硬件访问服务

安卓硬件访问服务 硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作。 由于硬件抽象层模块是使用C语言开发的&#xff0c; 而应用程序框架层中的硬件访问服务是使用Java语言开发的&#xff0c; 因此&#xff0c; 硬件访问服务必须通过Java本地接口&#xff08;Jav…

EPAI手绘建模APP演示板、材质编辑器、样式编辑器

(11) 更多 图 74 更多工具栏 ① 演示板&#xff1a;打开关闭演示板。演示板用来显示从设备导入的模型图纸图片或者打开模型建模教程网页&#xff0c;是建模过程中一个辅助功能。有些设备有小窗口功能有些没有&#xff0c;对于没有小窗口功能的设备&#xff0c;通过演示板能够在…

A Bug‘s Life (并查集)

//新生训练 #include <iostream> #include <algorithm> using namespace std; const int N 5000; int p[N], sz[N]; int n, m; int find(int x) {if (p[x] ! x)p[x] find(p[x]);return p[x]; } int main() {int T;scanf("%d", &T);for (int k 1; …

车载电子电器架构 —— 通信安全E2E Rollng counter

车载电子电器架构 —— 通信安全E2E Rollng counter 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要…

17_Scala面向对象高阶功能

文章目录 1.继承1.1 构造对象时,父类对象优于子类对象1.2父类主构造有参数,子类必须要显示地调用父类主构造器并传值 2.封装3.抽象3.1抽象定义3.2子类继承抽象类3.3抽象属性 4.伴生对象4.1创建类和伴生对象4.2调用 1.继承 –和Java一样,权限protected , public.父类定义子类用…

[嵌入式系统-67]:RT-Thread-组件:虚拟-设备文件系统DFS,以目录结构和文件的方式存储和管理各种各样的数据

目录 虚拟文件系统 1. DFS 简介 DFS 架构 POSIX 接口层 虚拟文件系统层 设备抽象层 2. 挂载管理&#xff1a;构建统一的文件系统目录 初始化 DFS 组件 注册文件系统 将存储设备注册为块设备 格式化文件系统 挂载文件系统 卸载文件系统 3. 文件管理 打开和关闭文…

分布式与一致性协议之一致哈希算法(三)

一致哈希算法 如何使用一致哈希算法实现哈希寻址 我们一起来看一个例子&#xff0c;对于1000万个key的3节点KV存储&#xff0c;如果我们使用一致哈希算法增加1个节点&#xff0c;即3节点集群变为4节点集群&#xff0c;则只需要迁移24.3%的数据,如代码所示 package mainimpor…

时间日志格式的统一和定制

返回当前格式的时间没有错误&#xff0c;但是不符合中国人的阅读习惯 解决&#xff1a; 方案一&#xff1a;JsonFormat 解决后端 传到 前端格式问题 依赖&#xff1a; <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jack…

brpc profiler

cpu profiler cpu profiler | bRPC MacOS的额外配置 在MacOS下&#xff0c;gperftools中的perl pprof脚本无法将函数地址转变成函数名&#xff0c;解决办法是&#xff1a; 安装standalone pprof&#xff0c;并把下载的pprof二进制文件路径写入环境变量GOOGLE_PPROF_BINARY_PA…

Spring Boot与JSP的浪漫邂逅:轻松构建动态Web应用的秘诀

本文介绍 Spring Boot 集成 JSP。 1、pom.xml 增加对 JSP 的支持 Spring Boot 的默认视图支持是 Thymeleaf 模板引擎&#xff0c;如果想要使用 JSP 页面&#xff0c;需要配置 servlet 依赖和 tomcat 的支持。 在 pom.xml 文件中增加如下代码&#xff1a; <!-- servlet依赖 -…