JAVA并发编程笔记(2)

《Java 并发编程的艺术》笔记——第2章 Java 并发机制的底层实现原理 文章目录2.1 volatile 的应用2.2 synchronized 的实现原理与应用2.2.1 Java 对象头2.2.2 锁的升级与对比2.3 原子操作的实现原理2.4 本章小结2.4 本章小结 声明: 本博客是本人在学习《Java 并发编程的艺术》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 Java 代码在编译后会变成 Java 字节码,字节码被类加载器加载到 JVM 里,JVM 执行字节码,最终需要转化为汇编指令在 CPU 上执行,Ja 阅读详情

可见性

Visibility这玩意儿很微妙,很容易违反直觉。要在多线程之间读写内存保证可见性,需要使用同步:always use the proper synchronization whenever data is shared across threads.

Stale Data
public class MutableInteger {
    private int value;

    public int  get() { return value; }
    public void set(int value) { this.value = value; }
}

对于这个程序,即使对setter方法加上同步也是不够的,其它读的线程依然可能读到修改之前或之后的数据。

对于64位的数字型变量,double或long,则不止是stale data的问题,因为JVM会将64位的读写操作分成两个32位的操作。所以有可能读到完全错误的数据。

锁和可见性

可以用锁来保证可见性。Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock.

image

Volatile变量

也可以用volatile来保证可见性。要使用volatile变量,必须满足下面三个条件

  1. Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
  2. The variable does not participate in invariants with other state variables; and
  3. Locking is not required for any other reason while the variable is being accessed.

锁既能保证原子性又能保证可见性,而volatile只能保证可见性。volatile最常用在表示完成、中断或者状态这样的标志位上。volatile不能保证像count++这种计数器的作用,除非能肯定只有一个线程去更新它。

后向投影算法(BPA)-SAR成像算法系列(二) SAR成像算法:后向投影算法(BPA)原理介绍及实现步骤解析。 阅读详情

相关推荐

华为交换机密码策略配置避坑指南:明文/密文、长度、复杂度,一个命令就出错

本文详细解析华为交换机密码策略配置的关键要点,包括密码长度、复杂度及等保合规要求。通过实战案例揭示常见配置误区,如明文/密文密码格式差异、复杂度检查联动机制等,帮助网络工程师避免安全漏洞。特别针对等保二级和三级要求,提供可直接落地的安全加固方案。

weixin_30879169的博客 368

java并发编程的艺术笔记2之Java内存模型

目录 二.Java内存模型 1.Java内存模型的基础 1.1并发编程模型的两个关键问题 1.2Java内存模型的抽象结构 1.3 从源代码到指令序列的重排序(为了提高性能) 1.4 并发编程模型的分类 1.5 happens-before (:一个操作的结果需要对另一个操作可见,可在不同线程) 2.重排序 3.顺序一致性 3.1顺序一致性内存模型的两大特性 3.2 顺...

worldeert的博客 264

为什么类型论是函数式编程的理想基础?

函数式编程(如Haskell、Scala、OCaml)以“函数为核心”“无副作用”“不可变数据”等特性著称,但它的“安全高效”并非凭空而来——背后的关键支撑是类型论。本文将聚焦“类型论如何支撑函数式编程”,从基础概念到具体案例,解释两者的本质联系。本文将按“故事引入→核心概念解释→关系拆解→原理+代码案例→实际应用→总结”的逻辑展开,用“乐高积木”“菜谱”等比喻贯穿全文,确保抽象理论可视化。类型论:程序的“接口规则手册”,定义类型和函数的约束;函数式编程。

AI天才研究院 694

java并发编程之美读书笔记-2

java并发编程之美读书笔记-2 每个Random实例里面都有一个原子性的种子变量用来记录当前的种子值,当要生成新的随机数时需要根据当前种子计算新的种子并更新回原子变量。在多线程下使用单个Random实例生成随机数时,当多个线程同时计算随机数来计算新的种子时,多个线程会竞争同一个原子变量的更新操作,由于原子变量的更新是CAS操作,同时只有一个线程会成功,所以会造成大量线程进行自旋重试,这会降低并...

tianyadaoke2020的博客 351

Mac用户必看:Parallels Desktop 18.1.1最新破解版安装与优化全攻略(附资源)

本文为Mac用户提供Parallels Desktop 18.1.1的详细安装与优化指南,涵盖虚拟化技术选型、专业级配置流程及性能调优技巧。重点解析Parallels Desktop在图形加速、系统资源调度方面的核心优势,并分享生产力增强技巧与典型应用场景实战方案,帮助用户最大化利用这一高效虚拟化工具。

weixin_29240343的博客 818

什么是 Agent 的 Context Window?为什么它是 Agent 工程中最核心的约束之一?

什么是 Agent 的 Context Window?为什么它是 Agent 工程中最核心的约束之一?

我哎GIS博客 814

Java并发编程学习笔记2

5.八锁现象 判断锁的是谁 锁new的对象或类的Class对象 8锁就是关于锁的8个问题 参考博客:https://www.cnblogs.com/itiaotiao/p/12651573.html 6.集合类不安全 并发下ArrayList不安全 解决方案 1、List<String> list=new Vector<>(); 2、List<String> list=new Collections.synchronizedList(new ArrayList<&g

a3026836480的博客 154

图解B+树的插入过程

B+ 树在现代数据库中很常见,如果我们了解它,在工作中可能对性能优化会有更好的帮助! 最近我一直在思考 B+ 树的高度是由什么决定的。知道我了解了 B+ 树的插入过程,才有一种恍然大悟的感觉! 网上的一些资料杂乱无章,不同的数据库可能还有对 B+ 树有不同的实现。但是万变不离其宗,B+ 树的定义,大致如下所示: 总结一下,B+ 树有下面 5 个重要的特点。 B+ 树包含 2 种类型的结点: 内部结点(也称索引结点)和叶子结点。 根结点本身即可以是内部结点,也可以是叶子结点。 根结点的关键字个数最

愿君出走半生,归来时仍是少年 2133

java并发编程的艺术笔记1-2章

第一章 并发编程的挑战 多线程带来的上下文切换的成本 频繁的切换上下文的效率开销某些情况下还不如单线程效率高 减少上下文切换的手段: 减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。 ·无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。 CAS算法。Java...

程序员!我当定了! 282

FANUC机器人S523 新款PN板卡与西门子PLC通信配置介绍

FANUC机器人S523 新款PN板卡与西门子PLC通信配置介绍

Robot_PLC_HMI_Automation 351

CDDT CST CDDT CSTTT

This is the second part of the SA8653 automotive CDDT configuration guide. It describes the matching rules and modification methods between CDDT and device‑tree DDTS. It explains CDT’s underlying logic and configuration in TZ, QNX and Android. It details C

qq_39257814的博客 1410

【笔记】【Java并发编程实战】2线程安全

注:本文为笔者阅读《JAVA并发编程实战》(Brian Goetz等注)一书的学习笔记,如有错漏,敬请指出。 线程安全的界定:当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步、在调用代码方无须作其他协调,这个类的行为依然是正确的,称这个类是线程安全的。(我的理解:找不出并行执行与串行执行结果相异的情况)构建并发程序要正确使用线程和锁。编写线程安全的代码,本质上是管理对状态的访问,而且通常是共享、可变的状态。一般而言,一个对象的状态就是它的数据(存储在状态变量中

julia_xueli的博客 799

Android系统开发面试指南:系统Launcher岗位解析

本文针对上海礼聪Android系统开发岗位(侧重系统Launcher、充电/电池/USB底层开发)提供面试指南。内容涵盖应用开发(启动流程优化)、系统底层(充电状态机、USBOTG)、编程能力(线程安全LRU实现)、问题排查(ANR分析)及沟通协作等核心考点。通过5类典型问题及技术深度解析,帮助候选人系统准备,重点考察Framework源码理解、系统调试能力和工程思维。建议结合PowerManagerService等模块源码和systrace工具进行实践准备,同时注重技术表达与协作能力的展现。

郑伟强dev的专栏 931

Java 并发编程学习笔记 2

Java 并发编程笔记

@码农充电站的专栏 442

老版QQ原生表情gif动态

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

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Java并发编程实战笔记—— 并发编程2

1、ThreadLocal   Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作。因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有一个指向同一个ThreadLocal变量的引用,但是这两个线程依然不能看到彼此的ThreadLocal变量域。ThreadLocal类提供了get和set等访问接口,这些方法为每个线程都存有一个独立的副本,因此每次get总...

weixin_30426879的博客 85

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

《Java并发编程的艺术》读后笔记-part2

在我们了解实现原理之前先了解一下CPU的术语,便于后续理解。volatile是如何来保证可见性的呢?我们这里用汇编指令来具体解析有volatile和无volatile的区别。Java代码:// instance是volatile变量转变成的汇编代码,如下:有volatile变量修饰的共享变量进行写操作的时候会多出第二行汇编代码,通过查IA-32架构软件开发者手册可知,Lock将当前处理器缓存行的数据写回到系统内存。这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。

2401_85767131的博客 505

笔记《Java并发编程实战》[2]

结构化并发应用程序 1)任务执行:当围绕“任务执行”来设计应用程序结构时,第一步就是要找出清晰的任务边界。在理想情况下,各个任务之间是相互独立的:任务并不依赖于其他任务的状态、结果或边界效应。【如:大多数服务器应用程序:以独立的客户请求为边界。Web服务器、邮件服务器、文件服务器、EJB服务器以及数据库服务器等,均通过网络接受远程客户的连接请求】 2)任务取消原因:用户请求取消、有时间现在的操...

三思而后行 156

Java并发编程实战读书笔记-Chapter2

当多个线程访问某个类时,这个类始终都能表现出正确的行为(某个类的行为与其规范完全一致),那么就称这个类是线程安全的。示例:无状态的Servlet(这个Servlet从请求中提取数值,执行因数分解,然后将结果封装到该Servlet的响应中)} }StatelessFactorizer 是无状态的,计算过程中的临时状态仅存在于线程栈上的局部变量中,并且只能由正在执行的线程访问。

weixin_42583701的博客 119

Java并发编程的艺术读书笔记2

上文结尾写到循环CAS实现原子操作 java中可以通过锁和循环CAS的方式实现原子操作 使用循环CAS实现原子操作,JVM中CAS操作正是利用了处理器提供的CMPXCHG实现的,自旋CAS实现的基本思路是循环进行CAS操作成功为止, CAS存在ABA问题,a->b->a好像a没有变 使用版本号可解决 循环时间长开销大 JVM提供pause,使cpu不消耗过多资源, 避免退出循环时因内存顺序冲突引起CPU流水线清空. 只能保证一个共享变量的原子操作. 合并变量. 使用...

qq_35557621的博客 134

Java 并发编程的艺术笔记——第2章 Java并发机制的底层实现原理

2.1 volatile volatile是轻量级的synchronized,如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。 volatile的两条实现原则: Lock前缀指令会引起处理器缓存回写到内存。 一个处理器的缓存回写到内存会导致其他处理器的缓存无效。 volatile的使用优化 追加64字节能够提高并发编程。 在两种场景下不应该使用这种方式: 缓存行非64字节宽的处理器; 共享变量不会被频繁地写; 2.2

qq_31683033的博客 207

Java并发编程实战读书笔记-Chapter5-2

在某些情况下,这种方式是非常合适的(例如,在服务器应用程序中,没有任何客户请求服务),而在其他一些情况下,这也表示需要调整生产者线程数量和消费者线程数量之间的比率,从而实现更高的资源利用率(例如,在“网页爬虫[Web Crawler]”或其他应用程序中,有无穷的工作需要完成)。这样你就能够创建更多灵活的策略来处理负荷过载的情况,例如减轻负载,将多余的工作项序列化并写入磁盘,减少生产者线程的数量,或者通过某种方式来抑制生产者线程。同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。

weixin_42583701的博客 207

JAVA 并发编程的艺术笔记(2.1 volatile的应用)

2.1.1 volatile 的定义与实现原理 java编程语言允许线程访问共享变量,为了确保共享变量能被准准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。 如果一个字段被声明成voliatile,java线程内存模型确保所有线程看到这个变量的值是一致的。 相关cpu术语: (图省略) 内存屏障(memory barriers) 是一组处理器指令,用于实现对内存操作的顺序限制 缓冲行(cache line) 缓存中可以分配的最小储存单位。处理器填写缓存线时会加载整个缓存线 原子操作(a

weixin_43143009的博客 148

Java多线程并发编程学习笔记【基础知识2】

一、多线程并发编程概念 首先需要分清并发和并行的概念。并发是指同一时间段有多个任务同时执行,而并行指的是在单位时间内有多个任务同时在执行。并发任务是建立在一段时间内cpu不断切换任务的基础上的,所以单核单线程cpu每个时间点只能执行一个任务,而并行是同一时间就有多个任务在执行,任务在不同的cpu上(针对单线程cpu而言)执行。 1、并发需要解决的问题 不同线程之间的读写操作,导致共享变量的内...

zhengtuqi的博客 318

《Java 并发编程实战》阅读笔记2系列:对象的安全共享

对象的安全共享 对象的安全共享 可见性 概述 失去可见性的危害 对抗可见性问题的法宝:volatile! 特点 两个特点的实现原理! Java 内存模型中对 volatile 变量定义的特殊规则 与 synchronized 的区别 应用场景: 通过确保状态不被发布来保证安全性 发布与溢出 发布 发布方法: 溢出 一个简单的溢出过程 this 引用溢出! 线程封闭 栈封闭 ThreadLocal 类 ThreadLocal 实现原理 不可变对象 定义 使用

Viper的程序员修炼手册 369

《java并发编程实战》读书笔记2

3.共享变量     编写正确的并发程序的关键在于对共享的、可变的状态进行访问管理。 3.1可见性     可见性是微妙的,这是因为可能发生错误的事情总是与直觉大相庭径。在一个单线程化的环境里,如果想一个变量先写入值,然后在没有写干涉的情况下读取这个变量,你希望能得到相同的 返回值。这看起来是很自然的。但是当读和写发生在不同的线程中时,情况却根本不是这样。为了确保跨线程写入的内存可见性,你必须使用...

weixin_40839342的博客 172

java并发编程学习笔记2

//已废除,勿使用 public void resume(); //已废除,勿使用 public void suspend(); //已废除,勿使用 public static void sleep(long millis); public static void sleep(long millis,int nan

luchi007的专栏 147
上一篇: 还是得记点笔记
下一篇: JAVA并发编程笔记(3)
windsome
博客等级 码龄19年 5粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值