并发开篇——带你从0到1建立并发知识体系的基石

機器學習基石 机器学习基石(Machine Learning Foundations) 作业1 习题解答 大家好,我是Mac Jiang,今天和大家分享coursera-NTU-機器學習基石(Machine Learning Foundations)-作业1的习题解答。笔者是在学习了Ng的Machine Learning之后开始学习这门课程的,但还是感觉收获颇丰。Ng的课程主要站在计算机专业的角度,教你如何使用机器学习,注重方法而不是数学推导,是一门很好的入门教程;而林轩田老师的机器学习基石是站在统计 阅读详情

前言

在本篇文章当中主要跟大家介绍并发的基础知识,从最基本的问题出发层层深入,帮助大家了解并发知识,并且打好并发的基础,为后面深入学习并发提供保证。本篇文章的篇章结构如下:

并发的需求

  • 我们常用的软件就可能会有这种需求,对于一种软件我们可能有多重需求,程序可能一边在运行一边在后台更新,因此在很多情况下对于一个进程或者一个任务来说可能想要同时执行两个不同的子任务,因此就需要在一个进程当中产生多个子线程,不同的线程执行不同的任务。
  • 现在的机器的CPU核心个数一般都有很多个,比如现在一般的电脑都会有4个CPU,而每一个CPU在同一个时刻都可以执行一个任务,因此为了充分利用CPU的计算资源,我们可以让这多个CPU同时执行不同的任务,让他们同时工作起来,而不是空闲没有事可做。

  • 还有就是在科学计算和高性能计算领域有这样的需求,比如矩阵计算,如果一个线程进行计算的话需要很长的时间,那么我们就可能使用多核的优势,让多个CPU同时进行计算,这样一个计算任务的计算时间就会比之前少很多,比如一个任务单线程的计算时间为24小时,如果我们有24个CPU核心,那么我们的计算任务可能在1-2小时就计算完成了,可以节约非常多的时间。

并发的基础概念

在并发当中最常见的两个概念就是进程和线程了,那什么是进程和线程呢?

  • 进程简单的说来就是一个程序的执行,比如说你再windows操作系统当中双击一个程序,在linux当中在命令行执行一条命令等等,就会产生一个进程,总之进程是一个独立的主体,他可以被操作系统调度和执行。
  • 而线程必须依赖进程执行,只有在进程当中才能产生线程,现在通常会将线程称为轻量级进程(Light Weight Process)。一个进程可以产生多个线程,二者多个线程之间共享进程当中的某些数据,比如全局数据区的数据,但是线程的本地数据是不进行共享的。

你可能会听过进程是资源分配的基本单位,这句话是怎么来的呢?在上面我们已经提到了线程必须依赖于进程而存在,在我们启动一个程序的时候我们就会开启一个进程,而这个进程会像操作系统申请资源,比如内存,磁盘和CPU等等,这就是为什么操作系统是申请资源的基本单位。

你可能也听过线程是操作系统调度的基本单位。那这又是为什么呢?首先你需要明白CPU是如何工作的,首先需要明白我们的程序会被编译成一条条的指令,而这些指令会存在在内存当中,而CPU会从内存当中一一的取出这些指令,然后CPU进行指令的执行,而一个线程通常是执行一个函数,而这个函数也是会被编译成很多指令,因此这个线程也可以被CPU执行,因为线程可以被操作系统调度,将其放到CPU上进行执行,而且没有比线程更小的可以被CPU调度的单位了,因此说线程是操作系统调度的基本单位。

Java实现并发

继承Thread类

public class ConcurrencyMethod1 extends Thread {

    @Override
    public void run() {
        // Thread.currentThread().getName() 得到当前正在执行的线程的名字
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            // 新开启一个线程
            ConcurrencyMethod1 t = new ConcurrencyMethod1();
            t.start();// 启动这个线程
        }
    }
}
// 某次执行输出的结果(输出的顺序不一定)
Thread-0
Thread-4
Thread-1
Thread-2
Thread-3

上面代码当中不同的线程需要得到CPU资源,在CPU当中被执行,而这些线程需要被操作系统调度,然后由操作系统放到不同的CPU上,最终输出不同的字符串。

使用匿名内部类实现runnable接口

public class ConcurrencyMethod2 extends Thread {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    // Thread.currentThread().getName() 得到当前正在执行的线程的名字
                    System.out.println(Thread.currentThread().getName());
                }
            });
            thread.start();
        }
    }
}
// 某次执行输出的结果(输出的顺序不一定)
Thread-0
Thread-1
Thread-2
Thread-4
Thread-3

当然你也可以采用Lambda函数去实现:

public class ConcurrencyMethod3 {

    public static void main(String[] args) {
        for (int i=0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                System.out.println(Thread.currentThread().getName());
            });
            thread.start();
        }
    }
}
// 输出结果
Thread-0
Thread-1
Thread-2
Thread-4
Thread-3

其实还有一种 JDK 给我们提供的方法去实现多线程,这个点我们在后文当中会进行说明。

理解主线程和Join函数

假如现在我们有一个任务,子线程输出一下自己的线程的名字,在线程输出完自己的名字之后,主线程再输出字符串“线程执行完成”。

在完成上面的任务之前,首先我们需要明白什么是主线程和子线程,所谓主线程就是在执行Java程序的时候不是通过 new Thread 操作这样显示的创建的线程。比如在我们的非并发的程序当中,执行程序的线程就是主线程。

public class MainThread {

    public static void main(String[] args) {
        System.out.println("我是主线程");
    }
}

比如在上面的代码当中执行语句 System.out.println("我是主线程"); 的线程就是主线程。

public class MainThread {

    public static void main(String[] args) {
        // 下面这段代码是由主线程执行的
        // 主线程通过下面这段代码创建一个子线程
        Thread thread = new Thread(() -> {
            System.out.println("我是主线程创建的子线程");
        });
        // 这句代码也是主线程执行的
        // 主要意义就是主线程启动子线程
        thread.start();
        System.out.println("我是主线程");
    }
}

现在我们再来看一下我们之前的任务:

假如现在我们有一个任务,子线程输出一下自己的线程的名字,在线程输出完自己的名字之后,主线程再输出字符串“线程执行完成”。

上面的任务很明确就是主线程在执行输出自己线程的名字的语句必之前,须等待子线程执行完成,而在 Java 线程当中给我提供了一种方式,帮助我们实现这一点,可以保证主线程的某段代码可以在子线程执行完成之后再执行。

public class MainThread {

    public static void main(String[] args) throws InterruptedException {
        // 下面这段代码是由主线程执行的
        // 主线程通过下面这段代码创建一个子线程
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        // 这句代码也是主线程执行的
        // 主要意义就是主线程启动子线程
        thread.start();
        // 这句代码的含义就是阻塞主线程
        // 直到 thread 的 run 函数执行完成
        thread.join();
        System.out.println(Thread.currentThread().getName());
    }
}
// 输出结果
Thread-0
main

上面代码的执行流程大致如下图所示:

我们需要知道的一点是 thread.join() 这条语句是主线程执行的,它的主要功能就是等待线程 thread 执行完成,只有 thread 执行完成之后主线程才会继续执行 thread.join() 后面的语句。

第一个并发任务——求 \(x^2\) 的积分

接下来我们用一个例子去具体体会并发带来的效果提升。我们的这个例子就是求函数的积分,我们的函数为最简单的二次函数 \(x^2\) ,当然我们就积分(下图当中的阴影部分)完全可以根据公式进行求解(如果你不懂积分也没有关系,下文我们会把这个函数写出来,不会影响你对并发的理解):

\[\int_0^{10} x^2\mathrm{d}x = \frac{1}{3}x^3+C \]

但是我们用程序去求解的时候并不是采用上面的方法,而是使用微元法:

\[\int_0^{10} x^2\mathrm{d}x =\sum_{ i= 0}^{1000000}(i * 0.00001) ^2 * 0.00001 \]

下面我们用一个单线程先写出求 \(x^2\) 积分的代码:

public class X2 {

  public static double x2integral(double a, double b) {
    double delta = 0.001;
    return x2integral(a, b, delta);
  }

  /**
   * 这个函数是计算 x^2 a 到 b 位置的积分
   * @param a 计算积分的起始位置
   * @param b 计算积分的最终位置
   * @param delta 表示微元法的微元间隔
   * @return x^2 a 到 b 位置的积分结果
   */
  public static double x2integral(double a, double b, double delta) {
    double sum = 0;
    while (a <= b) {
      sum += delta * Math.pow(a, 2);
      a += delta;
    }
    return sum;
  }

  public static void main(String[] args) {
    // 这个输出的结果为 0.3333333832358528
    // 这个函数计算的是 x^2 0到1之间的积分
    System.out.println(x2integral(0, 1, 0.0000001));
  }
}

上面代码当中的函数 x2integral 主要是用于计算区间 \([a, b]\) 之间的二次函数 \(x^2\) 的积分结果,我们现在来看一下如果我们想计算区间 [0, 10000] 之间的积分结果且 delta = 0.000001 需要多长时间,其中 delta 表示每一个微元之间的距离。

public static void main(String[] args) {
    long start = System.currentTimeMillis();
    System.out.println(x2integral(0, 10000, 0.000001));
    long end = System.currentTimeMillis();
    System.out.println(end - start);
}

从上面的结果来看计算区间 [0, 10000] 之间的积分结果且 delta = 0.000001 ,现在假设我们使用 8 个线程来做这件事,我们改如何去规划呢?

因为我们是采用 8 个线程来做这件事儿,因此我们可以将这个区间分成 8 段,每个线程去执行一小段,最终我们将每一个小段的结果加起来就行,整个过程大致如下。

首先我们先定义一个继承 Thread 的类(因为我们要进行多线程计算,所以要继承这个类)去计算区间 [a, b] 之间的函数 \(x^2\) 的积分:

class ThreadX2 extends Thread {
    private double a;
    private double b;
    private double sum = 0;
    private double delta = 0.000001;

    public double getSum() {
        return sum;
    }

    public void setSum(double sum) {
        this.sum = sum;
    }

    public double getDelta() {
        return delta;
    }

    public void setDelta(double delta) {
        this.delta = delta;
    }

    /**
   * 重写函数 run
   * 计算区间 [a, b] 之间二次函数的积分
   */
    @Override
    public void run() {
        while (a <= b) {
            sum += delta * Math.pow(a, 2);
            a += delta;
        }
    }

    public double getA() {
        return a;
    }

    public void setA(double a) {
        this.a = a;
    }

    public double getB() {
        return b;
    }

    public void setB(double b) {
        this.b = b;
    }
}

我们最终开启8个线程的代码如下所示:

public static void main(String[] args) throws InterruptedException {
	// 单线程测试计算时间
    System.out.println("单线程");
    long start = System.currentTimeMillis();
    ThreadX2 x2 = new ThreadX2();
    x2.setA(0);
    x2.setB(1250 * 8);
    x2.start();
    x2.join();
    System.out.println(x2.getSum());
    long end = System.currentTimeMillis();
    System.out.println("花费时间为:" + (end - start));
    System.out.println("多线程");
	
    // 多线程测试计算时间
    start = System.currentTimeMillis();
    ThreadX2[] threads = new ThreadX2[8];
    for (int i = 0; i < 8; i++) {
        threads[i] = new ThreadX2();
        threads[i].setA(i * 1250);
        threads[i].setB((i + 1) * 1250);
    }
    // 这里要等待每一个线程执行完成
    // 因为只有执行完成才能得到计算的结果
    for (ThreadX2 thread : threads) {
        thread.start();
    }
    for (ThreadX2 thread : threads) {
        thread.join();
    }
    end = System.currentTimeMillis();
    System.out.println("花费时间为:" + (end - start));
    double ans = 0;
    for (ThreadX2 thread : threads) {
        ans += thread.getSum();
    }
    System.out.println(ans);
}
// 输出结果
单线程
3.333332302493948E11
花费时间为:14527
多线程
花费时间为:2734
3.333332303236695E11
单线程多线程(8个线程)
计算结果3.333332302493948E113.333332303236695E11
执行时间145272734

从上面的结果来看,当我们使用多个线程执行的时候花费的时间比单线程少的多,几乎减少了7倍,由此可见并发的“威力”。

FutureTask机制

在前文和代码当中,我们发现不论是我们继承自 Thread 类或者写匿名内部内我们都没有返回值,我们的返回值都是 void ,那么如果我们想要我们的 run 函数有返回值怎么办呢? JDK 为我们提供了一个机制,可以让线程执行我们指定函数并且带有返回值,我们来看下面的代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FT {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new MyCallable());
        Thread thread = new Thread(task);
        thread.start();
        // get 函数如果结果没有计算出来
        // 主线程会在这里阻塞,如果计算
        // 出来了将返回结果
        Integer integer = task.get();
        System.out.println(integer);
    }
}

class  MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("线程正在执行");
        return 101;
    }
}
// 输出结果
线程正在执行
101

从上面的继承结构我们可以看出 FutureTask 实现了 Runnable 接口,而上面的代码当中我们最终会将一个 FutureTask 作为参数传入到 Thread 类当中,因此线程最终会执行 FutureTask 当中的 run 方法,而我们也给 FutureTask 传入了一个 Callable 接口实现类对象,那么我们就可以在 FutureTask 当中的 run 方法执行我们传给 FutureTask 的 Callable 接口中实现的 call 方法,然后将 call 方法的返回值保存下来,当我们使用 FutureTask 的 get 函数去取结果的时候就将 call 函数的返回结果返回回来,在了解这个过程之后你应该可以理解上面代码当中 FutureTask 的使用方式了。

需要注意的一点是,如果我们在调用 get 函数的时候 call 函数还没有执行完成, get 函数会阻塞调用 get 函数的线程,关于这里面的实现还是比较复杂,我们在之后的文章当中会继续讨论,大家现在只需要在逻辑上理解上面使用 FutureTask 的使用过程就行。

总结

在本篇文章当中主要给大家介绍了一些并发的需求和基础概念,并且使用了一个求积分的例子带大家切身体会并发带来的效果提升,并且给大家介绍了在Java当中3中实现并发的方式,并且给大家梳理了一下 FutureTask 的方法的大致工作过程,帮助大家更好的理解 FutureTask 的使用方式。除此之外给大家介绍了join函数,大家需要好好去理解这一点,仔细去了解join函数到底是阻塞哪个线程,这个是很容搞错的地方。

HTTP1.0、HTTP 1.1、HTTP 2.0主要区别 HTTP1.0、HTTP 1.1、HTTP 2.0之间的主要区别 HTTP1.0与HTTP 1.1的主要区别 长连接 节约带宽 HOST域 HTTP1.1与HTTP 2.0的主要区别 多路复用 数据压缩 服务器推送 一、HTTP1.0与HTTP 1.1的主要区别 长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。HTTP 阅读详情

相关推荐

手把手拆解DGX GB200 NVL72:1个机柜如何塞进72块GPU?详解NVLink Switch铜缆背板设计

本文深度解析英伟达DGX GB200 NVL72系统如何通过NVLink Switch铜缆背板设计,在标准42U机柜中集成72块B200 GPU,实现1800GB/s的超高带宽。文章详细介绍了模块化架构、铜缆互连技术、液冷散热方案和高密度供电系统等核心创新,为AI算力需求提供突破性解决方案。

red88的博客 1592

业务并发需求的实现

在许多大型项目中,通常有如下需求,业务扩展的时候,比如说人员管理,按各个地区进行分库处理。 打个比方:查询一个人的信息,输入身份证号(举例而已,代表唯一),北京有一套用户表,上海有一套一样的用户表,江西也有一套一样的用户表等等,多数据源实例。 需求:根据身份证号获取数据源信息,即我要查询哪个数据库信息才能查到。 新手思路: 遍历各个数据库嘛,这么简单的事。 但是有没有想过,挨个挨个去...

huangbaokang的博客 1368

HttpClient跳过HTTPS证书验证的3种实战方法(含完整代码示例)

本文详细介绍了HttpClient跳过HTTPS证书验证的3种实战方法,包括自定义TrustManager、SSLContext配置和HttpClientBuilder高级定制,并提供完整代码示例。这些方法适用于开发和测试环境,帮助开发者快速解决自签名证书或未认证证书导致的HTTPS请求失败问题,但需注意生产环境的安全风险。

weixin_29213655的博客 530

Java Concurrent处理并发需求

java5开始,增加了concurrent api,用于并发处理。比如起多个线程并发从网络上下载图片,然后在本地显示。 这里写个简单的代码,来说明如何使用concurrent api提供的线程连接池。 运行结果类似这样: start do 1 task … >>main thread end. start do 2 task … start do

忧郁的小鱼儿 331

基于RK3562J开发板的MCP2518FD CAN-FD控制器驱动适配与测试指南

本文详细介绍了在RK3562J开发板上适配MCP2518FD CAN-FD控制器驱动的完整流程。内容涵盖内核驱动配置、设备树修改、编译烧录以及实际通信测试,重点分享了调试方法,旨在帮助开发者快速为嵌入式系统扩展高速CAN-FD通信能力,适用于汽车电子、工业控制等场景。

jenkins8butler的博客 496

用LTspice仿真CMOS反相器功耗?这份避坑指南能省你3天调试时间

本文详细介绍了如何使用LTspice准确仿真CMOS反相器的功耗,包括动态功耗、短路功耗和静态功耗的测量技巧。通过工程实践指南,帮助电子工程师避开常见陷阱,优化仿真参数设置,提升仿真结果的可靠性,节省调试时间。

w7x8y9z的博客 190

带你从0到1建立并发知识体系的基石

前言在本篇文章当中主要跟大家介绍并发的基础知识,从最基本的问题出发层层深入,帮助大家了解并发知识,并且打好并发的基础,为后面深入学习并发提供保证。本篇文章的篇章结构如下:​编辑切换为居中添加图片注释,不超过 140 字(可选)并发的需求我们常用的软件就可能会有这种需求,对于一种软件我们可能有多重需求,程序可能一边在运行一边在后台更新,因此在很多情况下对于一个进程或者一个任务来说可能想要同时执行两个不同的子任务,因此就需要在一个进程当中产生多个子线程,不同的线程执行不同的任务。

m0_63437643的博客 88

后仿真中《SDF反标必懂连载篇》之 Negative Delay (理论篇)

今天,学习一下SDF文件中的负数延时问题。比如下面的图片中的SETUPHOLD 中的hold time 为负数。

那么菜的博客 2578

带你从 0 到 1 建立并发知识体系的基石

在本篇文章当中主要给大家介绍了一些并发的需求和基础概念,并且使用了一个求积分的例子带大家切身体会并发带来的效果提升,并且给大家介绍了在 Java 当中 3 中实现并发的方式,并且给大家梳理了一下 FutureTask 的方法的大致工作过程,帮助大家更好的理解 FutureTask 的使用方式。除此之外给大家介绍了 join 函数,大家需要好好去理解这一点,仔细去了解 join 函数到底是阻塞哪个线程,这个是很容搞错的地方。

m0_73311735的博客 77

勇闯dify v1.0.0之设置模型供应商。解决:Reached maximum retries (3) for URL https://marketplace.dify.ai/

朋友们,大家好,今天带大家来勇闯dify v1.0.0。为什么叫勇闯呢?我就这么说吧,本来我昨天就想带大家勇闯v1.0.0的。但是dify的marketplace访问不了。公司的网和手机热点都试了,就是访问不了。我们连个模型都没有,还勇闯个球啊,对吧,就搁置了。今天,我赶紧看看这个marketplace好了没。一看,可以了。赶紧写下这篇博客,帮助同志们走出困境。

xiezhipu的博客 4617

【STM32项目】基于STM32设计的震动马达超声波电机高频震动——高级定时器PWM互补输出带死区控制__资料编号3

实现高级定时器互补输出带死区控制,实现震动/超声波电机/马达,高频震动。使用 STM32F103 芯片输出两路互补 PWM,并带有死区和刹车控制功能。定时器 1 通道 1 及其互补通道输出PWM,且带死区控。当定时器 1 的刹车输入引脚被拉高时,产生刹车时间,即定时器 8 停止输出 PWM。当刹车输入引脚被拉高时,通道 1 和通道 2 将从有波形输入状态转换成无效电平状态。

嵌入式阿齐Archie 6742

Java 高并发系列1-开篇

Java 高并发系列1-开篇 我们都知道在Android开发中, 一个Android程序启动之后会有一个主线程,也就是UI线程, 而网络加载数据, 本地文件长时间读写,图片压缩,等等,很多耗时操作会阻塞UI线程,到时ANR的产生,在Android 3.0 之后便不能在UI线程使用。 由此可见多线程的使用在Android开发中占地位是多么重要。 这个系列 我打算通过一个个的例子来说明多线程的基本...

samuelnotes的专栏 6893

把 SAP Fiori Launchpad 配置文件放进 MIME Repository:从上传、缓存控制到可访问路径的完整实践

文章摘要: 在 SAP Fiori 项目中,Launchpad 配置文件的部署是关键挑战,核心在于通过 MIME Repository 而非直接修改标准文件来实现稳定配置。与 BSP Repository 相比,MIME Repository 支持显式设置客户端缓存时间(如 SAP 推荐的 7 天),适合生产环境治理。配置文件需为 JSON 格式,部署时需确保路径可访问(通过 ICF node 和 external alias),并注意语法错误会导致静默失效。实操步骤包括:在 SE80 中创建专用目录、设置

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 94

从0到1带你了解Java高并发

a,使用threadlock:这是一个线程级别的变量,允许线程创建自己的变量副本,他与普通的变量相比,普通变量是将变量存放在堆中,而其是将变量存放在线程中,进而实现更好的封闭性;但是在使用其时要进行手动的调用remove()方法,不然会发生内存泄漏等危险问题。a,当线程池中的任务全都执行完后,那空闲的线程会到阻塞队列中等待任务的到来,但因为我们设置了最大线程数,所以多余的线程会被回收,当他们去拿任务然后得到的结果是null时,会自动结束线程,这个过程是cas自动竞争的,直到只剩下核心线程数数量。

Aoqiqianmo的博客 863

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

早点建立自己的知识体系

抽时间更新。这几天事太多。这个文章还是《技术面试系列》,上一篇文章看这里《关于技术面试的一点点体会》,还是我在协助面试很多人后的一些体会。不是很长。适合那些刚入行或者工作有几年的同学们。...

微信搜:import_bigdata,大数据领域硬核原创作者 330

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

如何建立自己的技术知识体系

这一份知识体系建立文章并不是要给出要学习的知识点,而是从比较宏观的层面描述如何建立相应的知识体系,就相当于建立一个骨架,有了骨架后,还离不开平时的积累来进行丰富知识体系。除了知识体系的建立,还要建立自己的能力体系。知识体系是为能力体系进行服务的,最终的目标是建立和工作岗位相匹配的能力体系。

一直在努力的小渣渣 804

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

从经典到量子:理解 |0⟩ 与 |1⟩ 的基石意义

摘要:量子比特(qubit)的状态由基态|0⟩和|1⟩构成,二者正交且可表示任意叠加态α|0⟩+β|1⟩。不同于经典比特的确定性,量子比特通过叠加原理实现概率性状态,其正交性保障了测量的可靠性。布洛赫球面直观展现了量子态的无限可能性,|0⟩和|1⟩分别位于球体两极。这种特性使量子计算具有并行处理优势,突破了经典计算的限制。|0⟩和|1⟩不仅是数学基础,也是物理载体和信息单元,为量子计算提供了全新的范式。

数字人生 2576

知识体系的建立方法很重要

一个好的学习方法,一种科学的记忆手段,配合合理的烂笔头打造出最强学霸的点线面知识体系之路。 文章目录艾宾浩斯遗忘曲线康奈尔笔记法费曼学习法目标教学纠错简化点线面自成体系 艾宾浩斯遗忘曲线 遗忘曲线由德国心理学家艾宾浩斯(H.Ebbinghaus)研究发现,描述了人类大脑对新事物遗忘的规律。人体大脑对新事物遗忘的循序渐进的直观描述,人们可以从遗忘曲线中掌握遗忘规律并加以利用,从而提升自我记忆能力。该曲线对人类记忆认知研究产生了重大影响。 时间间隔 记忆量 刚记完 100% 20分钟后 5

zhujohnle的专栏 4460

HTTP1.0和HTTP1.1和HTTP2.0的主要区别

HTTP1.0和HTTP2.0的主要区别

wtl666_6的博客 7436

如何搭建属于你自己个人知识体系1.0

本文为PMCAFF专栏作者停云出品感到最无助无力的时候,才是你真正觉醒的时候。——《悟空传》那就趁无力时,让自己觉醒吧。通过搭建自己的个人知识体系,抛开你那无用的知识焦虑和无用的碎片化阅...

pmcaff2008的博客 620

Java并发基石—CAS原理实战

CAS:CompareAndSwap 比较并交换定义:CAS 包含三个参数,分别是内存位置(V)、期望值(A)、更新值(B),也即是说内存位置的值和期望值是一致的,就是将值更新为更新值。CAS 本质上不属于锁的范畴,我们称它为“无锁”。但是因为自旋(死循环)的存在,会在循环内部进行处理。但是因为死循环,可能会导致 CPU 上升。CAS 会存在ABA 问题。

How many ten years in the life time? 771

0、并发编程知识体系

并发编程是Java语言的重要特性之一,它能使复杂的代码变得更简单,从而极大的简化复杂系统的开发。 并发编程可以充分发挥多处理器系统的强大计算能力,随着处理器数量的持续增长,如何高效的并发变得越来越重要。

江7城子的专栏 247
上一篇: 7种 实现web实时消息推送的方案
下一篇: Kubernetes调度概念与工作流程
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值