首页
留言板
友链
关于
Search
1
内测“合金弹头”嘿嘿
1,088 阅读
2
Nginx搭建一个简易的图床
1,043 阅读
3
Kettle循环遍历结果集作为参数传入转换
987 阅读
4
Maven3.3.9的安装与配置
534 阅读
5
Maven打包插件与idea
508 阅读
知识库
好奇猫
日常说
笔记本
登录
/
注册
Search
标签搜索
maven
Spring
vue
Java
Java代码
前端
idea
帆软
MySQL
git
CSS
游戏
Bootstrap
生活
网上冲浪
邮件配置
说说
Nginx
Excel
数据库调优
龙流
累计撰写
61
篇文章
累计收到
29
条评论
首页
栏目
知识库
好奇猫
日常说
笔记本
页面
留言板
友链
关于
搜索到
3
篇与
Java代码
的结果
2022-02-23
实例volatile关键字使用场景 了解volatile关键字作用
volatile用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。volatile很容易被误用,用来进行原子性操作。如果要深入了解volatile关键字的作用,就必须先来了解一下JVM在运行时候的内存分配过程。在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图:以上是JVM在运行时候的内存分配过程以后,我们开始真正深入的讨论volatile的具体作用public class VolatileTest extends Thread { boolean flag = false; int i = 0; public void run() { while (!flag) { i++; } } public static void main(String[] args) throws Exception { VolatileTest vt = new VolatileTest(); vt.start(); Thread.sleep(2000); vt.flag = true; System.out.println("stope" + vt.i); } }上面的代码是通过标记flag来控制VolatileTest线程while循环退出的例子!下面让我用伪代码来描述一下我们的程序首先创建 VolatileTest vt = new VolatileTest();然后启动线程 vt.start();暂停主线程2秒(Main) Thread.sleep(2000);这时的vt线程已经开始执行,进行i++;主线程暂停2秒结束以后将 vt.flag = true;打印语句 System.out.println("stope" + vt.i); 在此同时由于vt.flag被设置为true,所以vt线程在进行下一次while判断 while (!flag) 返回假 结束循环 vt线程方法结束退出!主线程结束上面的叙述看似并没有什么问题,“似乎”完全正确。那就让我们把程序运行起来看看效果吧,执行mian方法。2秒钟以后控制台打印stope-202753974。可是奇怪的事情发生了 程序并没有退出。vt线程仍然在运行,也就是说我们在主线程设置的 vt.flag = true;没有起作用。 说明:有的同学在测试上面代码的时候程序可以正常退出。那是因为你的JVM没有优化造成的。在DOC下面输入 java -version 查看 如果显示Java HotSpot(TM) ... Server 则JVM会进行优化 如果显示Java HotSpot(TM) ... Client 为客户端模式,需要设置成Server模式 设置方法问Google问题出现了,为什么我在主线程(main)中设置了vt.flag = true; 而vt线程在进行判断flag的时候拿到的仍然是false?那么按照我们上面所讲的 “JVM在运行时候的内存分配过程” 就很好解释上面的问题了。 首先 vt线程在运行的时候会把 变量 flag 与 i (代码3,4行)从“主内存” 拷贝到 线程栈内存(上图的线程工作内存) 然后 vt线程开始执行while循环while (!flag) { i++ }while (!flag)进行判断的flag 是在线程工作内存当中获取,而不是从 “主内存”中获取。i++; 将线程内存中的i++; 加完以后将结果写回至 "主内存",如此重复。然后再说说主线程的执行过程。 我只说明关键的地方vt.flag = true;主线程将vt.flag的值同样 从主内存中拷贝到自己的线程工作内存 然后修改flag=true. 然后再将新值回到主内存。这就解释了为什么在主线程(main)中设置了vt.flag = true; 而vt线程在进行判断flag的时候拿到的仍然是false。那就是因为vt线程每次判断flag标记的时候是从它自己的“工作内存中”取值,而并非从主内存中取值!这也是JVM为了提供性能而做的优化。那我们如何能让vt线程每次判断flag的时候都强制它去主内存中取值呢。这就是volatile关键字的作用。再次修改我们的代码public class VolatileTest extends Thread { volatile boolean flag = false; int i = 0; public void run() { while (!flag) { i++; } } public static void main(String[] args) throws Exception { VolatileTest vt = new VolatileTest(); vt.start(); Thread.sleep(2000); vt.flag = true; System.out.println("stope" + vt.i); } }在flag前面加上volatile关键字,强制线程每次读取该值的时候都去“主内存”中取值。在试试我们的程序吧,已经正常退出了。原文出处:https://www.cnblogs.com/xd502djj/p/9873067.html作者:懂俊杰
2022年02月23日
85 阅读
0 评论
0 点赞
2022-01-17
反射动态调用某个类某个方法
简单的通过配置文件加反射的方法执行某方法{collapse}{collapse-item label="普通方法反射调用" open}public static void main(String[] args){ /** * eg:txt配置文件class.txt或properties的配置文件 * className=xxx * methodName=xxx */ Properties prop = new Properties(); FileRead fr = new FileRead("MyProject\\class.txt"); prop.load(fr); fr.close(); String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); //通过反射来使用 Class<?> c = Class.forName(className); Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); Method m = c.getMethod(methodName); m.invoke(obj); }{/collapse-item}{collapse-item label="折叠标题二"} 折叠内容二{/collapse-item}{/collapse}
2022年01月17日
117 阅读
0 评论
0 点赞
2021-10-18
Java关于文件和目录的操作
{collapse}{collapse-item label="判断文件大小是否变化" open} 通过持续判断文件大大小有没有变化,在网络传输过程中,稳定的传输文件大小肯定会不断变大;当文件一段时间文件大小不变,不考虑其他情况(如断网),说明文件传输完成注意点:1、等待文件(非目录)读写完毕,费时的操作,不要放在主线程2、判断文件长度的方法不适用于粘贴复制操作的判断,粘贴复制一般file.length()时固定的不会有写入写出(test)public static boolean checkFileWritingOn(String fileName) throws Exception{ long oldLen = 0; long newLen = 0; File file = new File(fileName); while(true){ newLen = file.length(); if ((newLen - oldLen) > 0) { oldLen = newLen; System.out.println(file.length()); Thread.sleep(10000); } else { System.out.println("done"); return true; } } }{/collapse-item}{collapse-item label="获取文件创建时间、最后更新时间等" open} /** * 获取文件的创建时间 * @param file * @return */ public static Date getCreationTime(File file) throws IOException { if (file == null) { return null; }else { Path path = file.toPath(); BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); // 创建时间 Instant instant = attr.creationTime().toInstant(); Date fordate = Date.from(instant); return fordate; } // 更新时间 //Instant instant = attr.lastModifiedTime().toInstant(); // 上次访问时间 //Instant instant = attr.lastAccessTime().toInstant(); //String format = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.systemDefault()).format(instant); //return format; }{/collapse-item}{collapse-item label="获取某路径下的所有文件/文件夹" open} /** * 获取路径下的所有文件/文件夹 * @param rootDir 需要遍历的文件夹路径 * @param isAddDirectory 是否将子文件夹的路径也添加到list集合中 * @return */ public static List<String> getAllFile(String rootDir, boolean isAddDirectory){ List<String> list = new ArrayList<String>(); File baseFile = new File(rootDir); if (baseFile.isFile() || !baseFile.exists()) { return list; } File[] files = baseFile.listFiles(); for (File file : files) { if (file.isDirectory()) { if(isAddDirectory){ list.add(file.getAbsolutePath()); } list.addAll(getAllFile(file.getAbsolutePath(),isAddDirectory)); } else { list.add(file.getAbsolutePath()); } } return list; }{/collapse-item}{collapse-item label="复制文件到指定目录" open} /** * @param filePath * @param targetPath * @throws IOException */ public static void fileCope(String filePath, String targetPath) throws IOException { //获得流 FileInputStream fileInputStream = new FileInputStream(filePath); File targetFile = new File(targetPath); //获取父目录 File parentFile = targetFile.getParentFile(); //判断是否存在 if (!parentFile.exists()) { // 创建父目录文件夹 parentFile.mkdirs(); } //判断文件是否存在 if (!targetFile.exists()) { //创建文件 targetFile.createNewFile(); } //新文件输出流 FileOutputStream fileOutputStream = new FileOutputStream (targetFile); byte[] buffer= new byte[1024]; int len; //将文件流信息读取文件缓存区,如果读取结果不为-1就代表文件没有读取完毕,反之已经读取完毕 while ((len=fileInputStream.read(buffer))!=-1) { fileOutputStream.write(buffer, 0, len); fileOutputStream.flush(); } fileInputStream.close(); fileOutputStream.close(); }{/collapse-item}{/collapse}
2021年10月18日
186 阅读
0 评论
0 点赞