java并发编程笔记(四)--JMM内存模型

2023-11-17

1.计算机结构

QQ截图20220109114051

输入设备:就是我们的鼠标,键盘

存储器:对应的就是我们的内存,缓存

运算器和控制器共同组成了cpu

而输出设备就比如显示屏,打印机。

我们重点来聊一下缓存:

2.缓存

其实,当我们说计算机运行效率低下,速度慢,往往不是cpu的锅。而问题所在一般都是内存访问速度太慢。

CPU的运算速度和内存的访问速度相差比较大。这就导致CPU每次操作内存都要耗费很多等待时间。内存的读写速度成为了计算机运行的瓶颈。

于是就有了在CPU和主内存之间增加缓存的设计。最靠近CPU的缓存称为L1,然后依次是L2,L3和主内存。

CPU缓存模型如图下图所示。

QQ截图20220109114428

运行速度: L1cache >L2cache >L3cache >内存

所以,系统会先访问L1缓存>L2缓存>L3缓存>内存

具体的速度如下:

QQ截图20220109114528

3.java内存模型概念

Java内存模型,是Java虚拟机规范中所定义的一种内存模型,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别。

Java内存模型是一套规范,描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

具体如下:

JMM体现在以下几个方面

  • 原子性 - 保证指令不会受到线程上下文切换的影响
  • 可见性 - 保证指令不会受 cpu 缓存的影响
  • 有序性 - 保证指令不会受 cpu 指令并行优化的影响

图解如下:

QQ截图20220109114829

Java内存模型如上面所示:规定了工作内存和主内存的概念及其交互。

对共享数据的可见性、有序性、和原子性的规则和保障。

QQ截图20220109114927

工作内存和主内存可能在很多地方(cpu寄存器 缓存 或者主内存)

4.主内存和工作内存的交互

Java内存模型中定义了以下8种操作来完成,主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,虚拟机实现时必须保证下面提及的每一种操作都是原子的、不可再分的。

具体操作如下图:

QQ截图20220109115543

5.对主内存操作的三大问题

原子性问题描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n12CMVk2-1645791850665)(https://cdn.jsdelivr.net/gh/EngageRing/images01@master/codeImages/QQ截图20220220171059.51apaq2e26k0.webp)]

解决原子性问题

上锁!

QQ截图20220220171237

可见性问题描述

可见性问题指的是,因为JMM内存模型规范,线程访问主内存的数据后会将数据复制到一个自己的共享内存里,若此时将主内存里的数据更改,就会引起数据不一致的可见性问题。

例子:

static Boolean run = true;
	public static void main(String[] args) throws InterruptedException {
		new Thread(()->{
			while (run) {
				//如果run为真,则一直执行
			}
		}).start();

		Thread.sleep(1000);
		System.out.println("改变run的值为false");
		run = false;
	}

QQ截图20220220171525

可见性问题的解决方法

用volatile关键字

static volatile boolean run = true; 
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(()->{ 
        while(run){ // .... 
        
        } });
            t.start(); 
    Thread.sleep(1000); 
    run = false; // 线程t不会如预想的停下来 
}

QQ截图20220220171701

指的注意的是synchronized也可以保证代码内变量的可见性

static  boolean run = true; 
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(()->{ 
        while(run){ // .... 
        System.out.printIn();
        } });
            t.start(); 
    Thread.sleep(1000); 
    run = false; // 线程t不会如预想的停下来 
}

因为输出的底层:

public void println(String x) {
		//使用了synchronized关键字
        synchronized (this) {
            print(x);
            newLine();
        }
    }

代码也会停下来

但性能更低。。。

两阶段终止模式:用可见性关键字实现

// 停止标记用 volatile 是为了保证该变量在多个线程之间的可见性
// 我们的例子中,即主线程把它修改为 true 对 t1 线程可见
class TPTVolatile {

    private Thread thread;
 
    private volatile boolean stop = false;
 
 public void start(){
 
 thread = new Thread(() -> {
 while(true) {
 
     Thread current = Thread.currentThread();
 
 if(stop) {
 
     log.debug("料理后事");
 
     break;
 }
 try {

     Thread.sleep(1000);
 
     log.debug("将结果保存");
 
 } catch (InterruptedException e) {
  }
 
     // 执行监控操作
 }
 },"监控线程");
 
     thread.start();
 }
 public void stop() {
 
     stop = true;
 
     thread.interrupt();
 }
}

//使用

TPTVolatile t = new TPTVolatile();

t.start();

Thread.sleep(3500);

log.debug("stop");

t.stop();
11:54:52.003 c.TPTVolatile [监控线程] - 将结果保存
11:54:53.006 c.TPTVolatile [监控线程] - 将结果保存
11:54:54.007 c.TPTVolatile [监控线程] - 将结果保存
11:54:54.502 c.TestTwoPhaseTermination [main] - stop 
11:54:54.502 c.TPTVolatile [监控线程] - 料理后事

同步模式之犹豫模式

定义

Balking (犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么本线程就无需再做 了,直接结束返回,本质上是一种懒惰的思想,就是用到的时候创建,然后重复创建。

  • 用一个标记来判断该任务是否已经被执行过了
  • 需要避免线程安全问题
    • 加锁的代码块要尽量的小,以保证性能
package com.nyima.day1;

/**
 * @author Chen Panwen
 * @data 2020/3/26 16:11
 */
public class Test7 {
	public static void main(String[] args) throws InterruptedException {
		Monitor monitor = new Monitor();
		monitor.start();
		monitor.start();
		Thread.sleep(3500);
		monitor.stop();
	}
}

class Monitor {

	Thread monitor;
	//设置标记,用于判断是否被终止了
	private volatile boolean stop = false;
	//设置标记,用于判断是否已经启动过了
	private boolean starting = false;
	/**
	 * 启动监控器线程
	 */
	public void start() {
		//上锁,避免多线程运行时出现线程安全问题
		synchronized (this) {
            //重点在这行代码,已经启动过,第二次就会进行判断,启动过了,下次就
			if (starting) {
				//已被启动,直接返回
				return;
			}
			//启动监视器,改变标记
			starting = true;
		}
		//设置线控器线程,用于监控线程状态
		monitor = new Thread() {
			@Override
			public void run() {
				//开始不停的监控
				while (true) {
					if(stop) {
						System.out.println("处理后续任务");
						break;
					}
					System.out.println("监控器运行中...");
					try {
						//线程休眠
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						System.out.println("被打断了");
					}
				}
			}
		};
		monitor.start();
	}

	/**
	 * 	用于停止监控器线程
	 */
	public void stop() {
		//打断线程
		monitor.interrupt();
		stop = true;
	}
}
有序性问题描述

我们来看如下代码:

int num = 0;
boolean ready = false; 
// 线程1 执行此方法 
public void actor1(I_Result r) {
    if(ready) { 
        r.r1 = num + num;
    }else {
        r.r1 = 1;
    } }
// 线程2 执行此方法 
public void actor2(I_Result r) {
    num = 2;
    ready = true;
}

它有集中结果呢?

  • 情况1:线程1 先执行,这时 ready = false,所以进入 else 分支结果为 1
  • 情况2:线程2 先执行 num = 2,但没来得及执行 ready = true,线程1 执行,还是进入 else 分支,结果为1
  • 情况3:线程2 执行到 ready = true,线程1 执行,这回进入 if 分支,结果为 4(因为 num 已经执行过了)

这些都是基于我们上面学的分析出来的结果,但实际上结果还有一个 0

线程2 执行 ready = true,切换到线程1,进入 if 分支,相加为 0,再切回线程2 执行 num = 2

出现这种结果,说明发生了指令重排,引起了有序性问题。

那既然jvm的指令重排会引起有序性问题,那么为什么还要使用指令重排呢?

因为提高了指令地吞吐率

使用指令重排的原因
  • 事实上,现代处理器会设计为一个时钟周期完成一条执行时间长的 CPU 指令。为什么这么做呢?可以想到指令还可以再划分成一个个更小的阶段,例如,每条指令都可以分为: 取指令 - 指令译码 - 执行指令 - 内存访问 - 数据写回 这5 个阶段

QQ截图20220225195902

  • 在不改变程序结果的前提下,这些指令的各个阶段可以通过重排序组合来实现指令级并行
  • 指令重排的前提是,重排指令不能影响结果,例如
// 可以重排的例子 
int a = 10; 
int b = 20; 
System.out.println( a + b );

// 不能重排的例子 
int a = 10;
int b = a - 5;

现代 CPU 支持多级指令流水线,例如支持同时执行 取指令 - 指令译码 - 执行指令 - 内存访问 - 数据写回 的处理器,就可以称之为五级指令流水线。

这时 CPU 可以在一个时钟周期内,同时运行五条指令的不同阶段(相当于一 条执行时间长的复杂指令),IPC = 1,本质上,流水线技术并不能缩短单条指令的执行时间,但它变相地提高了指令地吞吐率 (cpu同一时间段不能执行相同阶段的指令,所以同时使用不同代码的不同阶段,吞吐量最高)

QQ截图20220225200201

在多线程环境下,指令重排序可能导致出现意料之外的结果

有序性问题解决办法

QQ截图20220220172545

volatile是怎么解决有序性和可见性的问题的呢?

volatile 原理

volatile的底层实现原理是内存屏障,Memory Barrier(Memory Fence)

  • 对 volatile 变量的写指令后会加入写屏障
  • 对 volatile 变量的读指令前会加入读屏障

而有了屏障之后,可见性和有序性就有了很好的解决。

  • 可见性
    • 写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
    • 读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中新数据
  • 有序性
    • 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
    • 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前

QQ截图20220225201352

QQ截图20220225201402

QQ截图20220225201409

QQ截图20220225201422

volatile实际上使用的时机很少,一般为了处理一个写多个读,或者后面所说的double-checked问题

有序性的理解

QQ截图20220220172653

有序性引起的double-check问题

QQ截图20220220172828

理解下就是:

QQ截图20220220145712

这是优点:double-checke机制可以减少重复创建对象的现象,提升效率。

但是忽略了有序性问题

我们创建对象时的字节码如下:

0: new #2 // class cn/itcast/jvm/t4/Singleton  分配空间
3: dup    //将引用地址放进操作数栈
4: invokespecial #3 // Method "<init>":()V  将对象完善
7: putstatic #4 // Field INSTANCE:Lcn/itcast/jvm/t4/Singleton; 将完善后的对象放进局部变量表

此时容易发生 4 ,7之间的指令重排,使得对象没完善之前就赋值给了INSTANCE对象,如果对象本来就很复杂,后面的线程就容易得到不完善的对象。

解决办法:

public final class Singleton {
    private Singleton() { }
    private volatile static  Singleton INSTANCE = null; 
    public static Singleton getInstance() {
        // 实例没创建,才会进入内部的 synchronized代码块 
        if (INSTANCE == null) { 
            synchronized (Singleton.class) { 
                // 也许有其它线程已经创建实例,所以再判断一次 
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                } } }
        return INSTANCE;
    } }

要注意:sychronized一定情况下也可以保证有序性的

QQ截图20220225155251

happens-before

QQ截图20220220173643

线程单例问题

单例模式有很多实现方法,饿汉、懒汉、静态内部类、枚举类,

单例模式又分为饿汉式和懒汉式

饿汉式:类加载就会导致该单实例对象被创建

懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建

我们来分别分析以下的几种情况

  • 饿汉式单例
// 问题1:为什么加 final    
//:以防止子类继承来随意篡改父类方法
// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例
//:创建返回值是Object的readResolve方法,返回我们创建的对象
public final class Singleton implements Serializable {
 // 问题3:为什么设置为私有? 是否能防止反射创建新的实例?
    //不能防止,私有化是为了满足单例的需要
 private Singleton() {}
 // 问题4:这样初始化是否能保证单例对象创建时的线程安全?
    //可以 final修饰的变量在类加载时会创建,安全性由jvm管理
 private static final Singleton INSTANCE = new Singleton();
 // 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由
    //是一种懒惰的思想,类的静态方法使用的时候才会初始化这个类,将它创建成静态方法,是为了使用时再创建,不使用不创建
 public static Singleton getInstance() {
 
     return INSTANCE;
 }
 public Object readResolve() {
 
     return INSTANCE;
 }
}
  • 枚举
// 问题1:枚举单例是如何限制实例个数的  
//该实例时枚举类里的一个私有化变量,不能再被创建

// 问题2:枚举单例在创建时是否有并发问题 
//该单例由final修饰,安全由jvm管理

// 问题3:枚举单例能否被反射破坏单例
//不能,枚举进行了保护

// 问题4:枚举单例能否被反序列化破坏单例
//枚举类对此进行了对应处理

// 问题5:枚举单例属于懒汉式还是饿汉式
//饿汉式

// 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做
enum Singleton { 
 
    INSTANCE; 

}
  • 普通的懒汉式单例
public final class Singleton {
 
    private Singleton() { }
 
    private static Singleton INSTANCE = null;
 
    // 分析这里的线程安全, 并说明有什么缺点  
    
    //线程是安全的,每一次都要使用sychronized锁,效率低下,同时可能因为代码的重新排序,

    public static synchronized Singleton getInstance() {
 
        if( INSTANCE != null ){
 
            return INSTANCE;
 
        } 
 
        INSTANCE = new Singleton();
 
        return INSTANCE;
 
    }
}
  • DCl
public final class Singleton {
 private Singleton() { }
 // 问题1:解释为什么要加 volatile ? 
    //防止创建对象时的重排序问题
 private static volatile Singleton INSTANCE = null;
 
 // 问题2:对比实现3, 说出这样做的意义 
    //创建了对象后就不用再次进入sychronized代码块,加大了效率
 public static Singleton getInstance() {
 
     if (INSTANCE != null) { 

         return INSTANCE;
 
     }
 
     synchronized (Singleton.class) { 
 
         // 问题3:为什么还要在这里加为空判断, 之前不是判断过了吗
           //防止首次添加时多个线程进入,多次创建对象
 
  if (INSTANCE != null) { // t2 
 
      return INSTANCE;
 }
 
         INSTANCE = new Singleton(); 
 
         return INSTANCE;
 } 
 }
}
  • 懒汉套饿汉
public final class Singleton {
 
 private Singleton() { }
 // 问题1:属于懒汉式还是饿汉式
    //懒汉式
 
    private static class LazyHolder {
 
        static final Singleton INSTANCE = new Singleton();
}
 // 问题2:在创建时是否有并发问题 
    //因为是final修饰,所以安全性由jvm管理

    public static Singleton getInstance() {
 
        return LazyHolder.INSTANCE;
 
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java并发编程笔记(四)--JMM内存模型 的相关文章

  • 在 JRE 级别限制密码套件

    我们的 Java 应用程序公开了许多不同的接口 SMTP FTP HTTP 并通过 SSL TLS 进行保护 现在的目标是限制这些接口上允许的密码套件仅包含 强 密码套件 我已经有了一个列表 并且很清楚如何使其适用于特定套接字 socket
  • 从字符串中提取整数并将它们添加到Java中[重复]

    这个问题在这里已经有答案了 我想从字符串中提取整数并将它们相加 Ex String s ab34yuj789km2 我应该从中得到整数的输出 825 即 34 789 2 825 这是一种方法 使用 String split public
  • Java中使用正则表达式确定字符串是否为URL [重复]

    这个问题在这里已经有答案了 可能的重复 检查字符串是否为有效 URL 的最佳正则表达式是什么 https stackoverflow com questions 161738 what is the best regular express
  • “此 GPIO 引脚已存在:”第二次出现 GPIO 1 异常

    我正在 Raspberry pi 和 java 上工作 通过使用 pi4j 使 LED 闪烁 一切都已清除并且工作正常 LED 按照代码闪烁 但是当我第二次运行时 它会导致以下错误 我已经搜索了很多有很多相同的问题没有明确的答案如何解决 任
  • 为什么这个基于java配置的Spring应用程序不能正常工作

    我最近开始了一个使用 Spring 框架的项目 目标是在没有 XML 配置文件 只有 Java 代码的情况下开发它 目前 我将以下文件添加到我的项目中 WebAppConfig java EnableWebMvc ComponentScan
  • 将数据传递到表单时的重定向后获取?

    我有几个场景 servlet 需要将数据从数据库检索到的记录传递到 JSP 中的表单 目前 我将此信息存储在请求中 使用 RequestDispatcher 转发到页面 一切都很好 然而 这不符合 PRG 模式 AFAIK 并且当然意味着刷
  • Java 7 中的 Beans Binding 将被什么取代?

    我在某处读到 我忘记了链接 Beans Binding 将不会成为 Java 7 的一部分 有人知道什么会取代它吗 另外 当前版本的 Java 中是否有 Bean 绑定的替代方案 我建议JGoodies 绑定 https binding d
  • 使用 TLS 证书 JDBC 连接到 Oracle 数据库

    我正在尝试用 Java 编写一个连接类来使用 JDBC 驱动程序连接到 Oracle 数据库 但我想保护用于连接到 Oracle 数据库的参数 例如 jdbcurl 用户名 密码 我必须使用 TLS 证书概念来连接到 Java 中的 Ora
  • 搜索 JTable 时 - 未获得正确的 ID

    所以我尝试在搜索名称后单击表 然后在其他表中编辑它 问题是我没有获得正确的 ID 而只获得第一个 ID JTable https i stack imgur com TnNIq png 搜索行动 https i stack imgur co
  • Spring 应用程序启动前的 Spring Boot 设置日志记录

    我有一个项目 在启动 SpringApplication 之前需要日志记录机制 我怎样才能做到这一点 我尝试设置自己的日志记录机制 LogManager getLogManager readConfiguration 但在 Spring 应
  • 使用 iText 在内存上生成在磁盘上生成的 PDF

    我正在从 Java 应用程序生成 PDF 并且效果很好 问题是 PDF 在磁盘上生成为 Document documento new Document PageSize A4 25 25 25 25 PdfWriter writer Pdf
  • Spring REST 控制器返回带有空数据的 JSON [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我有一个简单的 Spring Boot Web 应用程序 我正在尝试从服务器接收一些数据 控制器返回一个集合 但浏览器收
  • swing - 在 JPanel 上单击组件

    好的 我有一个带有 GridLayout 的 JPanel 网格的每个单元格都包含另一个 JPanel 我希望能够做的是在 下方 JPanel 上有一个侦听器 然后它告诉我单击了哪个 覆盖 JPanel 这样我就可以对它和周围的 JPane
  • Java - 在特定日期执行方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要在每年的特定日期执行一个方法 我该如何在java中执行此操作 Thanks Chris 按优先顺序排列 The Quartz htt
  • Spring Boot 中的外部化配置,多个应用程序在同一容器中运行

    我正在构建多个 Spring Boot 应用程序 这些应用程序将部署在同一个 servlet 容器上 但我很难让 Spring Boot 按照我想要的方式使用外部化配置文件 而不是像框架想要的那样 情况 多个 Spring Boot 应用程
  • 从流中过滤/删除无效的 xml 字符

    首先 我无法更改 xml 的输出 它是由第三方生成的 他们在 xml 中插入无效字符 我得到了 xml 字节流表示形式的 InputStream 除了将流消耗到字符串中并对其进行处理之外 是否有一种更干净的方法来过滤掉有问题的字符 我找到了
  • 将文件内容存储到数组中

    我的刽子手程序有问题 我真的认为我需要做的事情超出了我对java的理解 这是我的代码 import java io BufferedReader import java io FileReader import java io FileNo
  • JavaFX:在 WebView img 标签中未加载本地图像

    以下是我的代码 一切安好 我可以加载远程页面 我可以放置 HTML 内容 但我的img标签显示一个X标志表示无法加载图像 Note 我的图像与类位于同一个包中JavaFX在 Smiley 文件夹中 我可以列出所有图像 这意味着路径没有问题
  • 使用 Maven 将值附加到文件中

    我想在文件末尾附加一个值 但我无法确定要使用哪个插件 例子 我要附加的值 myValue file value1 value2 myValue 追加后 我知道我可以使用 antrun plugin 来做到这一点 但是可以使用 Maven 插
  • JVM 调试端口 7779 正在使用

    我正在使用 RAD 8 当我在调试模式下启动服务器时 它会显示一条错误消息 指出JVM debug port 7779 is in use 我多次遇到这个问题 因为我知道 RAD 使用了这个端口 所以我不得不停止这个过程窗口任务管理器 gt

随机推荐

  • 计算机组成原理定点源码一位乘,计算机组成原理课程设计-定点原码一位乘法器的设计.doc...

    计算机组成原理课程设计 定点原码一位乘法器的设计 课 程 设 计 报 告 课程设计名称 计算机组成原理课程设计 课程设计题目 定点原码一位乘法器的设计 院 系 计算机学院 专 业 班 级 4401102 学 号 208 姓 名 指导教师 完
  • mysql创建带密码的用户使用密码无法登录,但是不输入密码可以登录

    在cmd窗口 直接使用 mysql usa 可以登录 但是创建sa时候设置密码为123456 原因可能有两个 设置密码后没有强制刷新权限或者重启mysql服务 Mysql数据库的user表中有名字为空的用户名或root的密码为空 解决方法
  • np.where()函数的详细使用介绍

    看了很多博客 见到的没有一个给说清楚了 这里做个记录 这是python提供的函数说明 Help on function where in module numpy where where condition x y Return eleme
  • linux man php,linux man命令的使用

    linux man命令的使用 main 是最常见的帮助命令 也是 Linux 最主要的帮助命令 其基本信息如下 命令名称 man 英文原意 format and display the on line manual pages 所在路径 u
  • 第二个电商项目Bug点统计和解决方法

    第二个完成的项目 在完成项目后 我总结了那些自己感觉重要的BUG 1 BUG系列一 设置延时 导致Activity销毁后 延时中的PullToRefreshListView 为null Bug现象 Bug 85536 在网络不好情况下 快速
  • Nuitka 和 PyInstaller 对比

    一 什么是 Nuitka 和 PyInstaller 1 1 Nuitka Nuitka 是一个 Python 编译器 可以将 Python 代码转换成可执行的 C 代码 然后将其编译成本机可执行文件 与常规的 Python 解释器相比 使
  • 8.3 PowerBI系列之DAX函数专题-矩阵Matrix中高亮显示最大最小值

    需求 用颜色标量年度最大最小值 用颜色标示折线的最大值最小值 实现 在条件格式 规则 基于字段进行计算 度量值 is max min var displayed data calculatetable addcolumns summariz
  • 坚持天天写技术笔记

    恍恍惚惚
  • 用C语言编写一段堆排序算法

    include
  • 同步、异步和阻塞、非阻塞的区别与联系

    同步 异步和阻塞 非阻塞的概念 同步 在执行一个操作的时候需要等待当前操作执行完毕才能执行下一操作 相当于操作串行化 即执行当前函数的时候需要拿到当前函数的返回结果才可以继续执行 异步 在执行一个操作的时候不需要拿到返回结果 只需要拿到注册
  • 程序员必备的免费AI生产力(摸鱼)工具,最后一个,人手必备

    最近ChatGPT等AI技术风靡全球 对于普通大众来说 越来越多的人开始关注智能时代对我们生活的影响 它颠覆了写作 办公 绘画 音视频 图像处理 UI 设计等领域 并涌现出了一批具有颠覆性的应用 在程序员领域 许多 AI 工具已经涌现 如
  • Android fragment间的通讯

    1 使用FragmentPagerAdapter情况下 param viewpagerId viewpager id eg R id vp param position fragment 的位置 return private Fragmen
  • linux线程内存开销

    1 首先是线程自己栈 程序没设置过 就是默认的 ulimit s 中的值 现在一般都是10240 单位KB 2 跟版本有关 是否有 glibc 的 malloc per thread arenas 特性 有了这个特性 设置不好 一个新线程要
  • 2003 - Cant't connect to MySQL server on 'ip'(10060 "Unknown error")

    问题描述 今天在搭建服务器之后 安装好MySQL 启动成功 并且创建远程连接用户 用户名和密码都正确 使用Navicat远程连接抛出如下错误 2003 Cant t connect to MySQL server on 192 168 13
  • Go module的介绍及使用

    Go1 1 1版本发布 2018 08 24发布 已经过去几天 从官方的博客中看到 有两个比较突出的特色 一个就是今天讲的module 模块概念 目前该功能还在试验阶段 有些地方还需要不断的进行完善 在官方正式宣布之前 打算不断修正这种支持
  • 牛客网:美团2021校招笔试-编程题(通用编程试题,第10场)

    某比赛已经进入了淘汰赛阶段 已知共有n名选手参与了此阶段比赛 他们的得分分别是a 1 a 2 a n 小美作为比赛的裁判希望设定一个分数线m 使得所有分数大于m的选手晋级 其他人淘汰 但是为了保护粉丝脆弱的心脏 小美希望晋级和淘汰的人数均在
  • Vivido添加pynq-Z2开发板

    一 下载pynq z2开发板文件 下载地址 https www tulembedded com FPGA ProductsPYNQ Z2 html 二 将下载的文件解压到vivado安装的位置 如果boards目录下面没有boards fi
  • 软件测试自动化UI框架之生成测试报告

    设置报告 自动化测试最后的运行结果要以报告的形式呈现 报告的格式是web端网页 需要引入第三方库 不是唯一的 有很多 一般一个公司统一用一个 1 引入自动生成测试框架报告 2 创建测试报告生成文件夹 reports 3 写代码 框架的入口文
  • UE4开发七:UE4打包

    一 使用UFE打包 UFE Unreal Frontend 虚幻前端 简化加快游戏开发及测试任务的工具 它可以用来准备游戏构建 将游戏部署到设备上并进行启动 测试版本 4 18为例 注意 UE4官方文档原话是在UE4编辑器中启动UFE或者P
  • java并发编程笔记(四)--JMM内存模型

    1 计算机结构 输入设备 就是我们的鼠标 键盘 存储器 对应的就是我们的内存 缓存 运算器和控制器共同组成了cpu 而输出设备就比如显示屏 打印机 我们重点来聊一下缓存 2 缓存 其实 当我们说计算机运行效率低下 速度慢 往往不是cpu的锅