首页 文章 精选 留言 我的

精选列表

搜索[Java],共10000篇文章
优秀的个人博客,低调大师

关于java线程中stop interrupt daemon wait notify

一。关于终止线程stop与interrupt 一般来说,线程执行结束后就变成消亡状态,乍看之下我们并不需要人为进行干预(人为停止线程),不过凡事都有例外吧,在服务器或者其他应用场景下,线程为了提供服务而一直在不停的运转,因此必要时刻我们还需“人为干涉的”。 通常情况下,终止线程有两种方式:stop与interrupt 1) stop:暴力的停止线程(不管线程执行到哪段代码,立刻干掉),这个方法因为过于暴力会导致安全问题,因此JDK不推荐使用。 2) interrupt:优雅停止,调用该方法会通知线程可以进行停止操作了,此时线程只是变成可停止状态(thread.isInterrupted的值为true),实际上并没有停止 请看下段代码: 1 package com.bdqn.lyrk.basic; 2 3 /** 4 * 一个线程设置共享变量的值,保持ID与name值相同 5 * 另外一个线程读取共享变量的值,发现ID与name值不同时打印 6 * 7 * @author chen.nie 8 * @date 2018/1/30 9 **/ 10 public class StopThreadUnsafe { 11 12 public static User user = new User(); 13 14 public static class User { 15 private int id; 16 private String name; 17 18 public int getId() { 19 return id; 20 } 21 22 public void setId(int id) { 23 this.id = id; 24 } 25 26 public String getName() { 27 return name; 28 } 29 30 public void setName(String name) { 31 this.name = name; 32 } 33 34 public User() { 35 id = 0; 36 name = "0"; 37 } 38 39 @Override 40 public String toString() { 41 return "User [id=" + id + ",name=" + name + "]"; 42 } 43 } 44 45 public static class ChangeObjectThread extends Thread { 46 47 @Override 48 public void run() { 49 while (true) { 50 synchronized (user) { 51 if (Thread.currentThread().isInterrupted()) { 52 break; 53 } 54 int i = (int) System.currentTimeMillis() / 1000; 55 user.setId(i); 56 try { 57 Thread.sleep(100); 58 } catch (InterruptedException e) { 59 Thread.currentThread().interrupt(); 60 } 61 user.setName("" + i); 62 63 } 64 Thread.yield(); 65 } 66 } 67 } 68 69 public static class ReadObjectThread extends Thread { 70 71 @Override 72 public void run() { 73 while (true) { 74 synchronized (user) { 75 if (user.getId() != Integer.parseInt(user.getName())) { 76 System.out.println(user); 77 } 78 } 79 Thread.yield(); 80 } 81 } 82 } 83 } View Code Main方法: 1 package com.bdqn.lyrk.basic; 2 3 public class Main { 4 public static void main(String[] args) throws InterruptedException { 5 new StopThreadUnsafe.ReadObjectThread().start(); 6 while (true) { 7 StopThreadUnsafe.ChangeObjectThread thread = new StopThreadUnsafe.ChangeObjectThread(); 8 thread.start(); 9 Thread.sleep(200); 10 thread.stop(); 11 // thread.interrupt(); 12 } 13 } 14 } View Code 此时调用stop终止线程时,得到如下结果 User [id=1197577,name=1197576] User [id=1197577,name=1197576] User [id=1197577,name=1197576] User [id=1197577,name=1197576] User [id=1197578,name=1197577] 原因很简单:stop方法会释放对象锁,并终止线程,当线程还没有与name赋值时,已经被干掉了因此其他线程在读取时,很有可能读到NAME与ID值不一致的情况 二。守护线程Daemon 守护线程顾名思义,是系统的守护者,这个线程为系统的运行默默提供服务,当系统任务运行完毕,守护线程也就完成使命了,比如说垃圾回收线程,JIT线程都是守护线程,设置守护线程的方式:在调用start方法前,通过线程对象.setDaemon(true) 代码如下: 1 package com.bdqn.lyrk.basic; 2 3 public class DaemonDemo { 4 public static class DaemonT extends Thread { 5 @Override 6 public void run() { 7 while (true){ 8 System.out.println("I am alive"); 9 try { 10 Thread.sleep(1000); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 } 15 } 16 } 17 18 public static void main(String[] args) throws InterruptedException { 19 DaemonT daemonT = new DaemonT(); 20 daemonT.setDaemon(true); 21 daemonT.start(); 22 Thread.sleep(5000); 23 } 24 } View Code 运行结果 I am alive I am alive I am alive I am alive I am alive Process finished with exit code 0 我们可以看到,当主线程执行完毕后,守护线程也随之结束 三。wait与notify wait与notify是多线程协同工作的最基本手段,可是这两个方法属于Object的方法,当需要使用wait和notify时,必须配合synchronized使用,此时调用wait方法,当前线程会进入等待队列并释放当前的对象锁,直到线程被唤醒(notify),notify方法会随机唤醒一个在等待队列中的线程,notifyAll方法则唤醒所有在等待队列中的线程 代码示例: 1 package com.bdqn.lyrk.basic; 2 3 public class SimpleWN { 4 public static final Object object = new Object(); 5 6 public static class T1 extends Thread { 7 8 @Override 9 public void run() { 10 synchronized (object) { 11 System.out.println("开始执行线程..."); 12 try { 13 object.wait(); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 System.out.println("结束执行线程..."); 18 } 19 } 20 } 21 22 public static class T2 extends Thread { 23 @Override 24 public void run() { 25 synchronized (object) { 26 System.out.println("5秒后准备唤醒线程.."); 27 try { 28 Thread.sleep(5000); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 object.notify(); 33 } 34 } 35 } 36 37 public static void main(String[] args) { 38 T1 t1 = new T1(); 39 T2 t2 = new T2(); 40 t1.start(); 41 t2.start(); 42 } 43 } View Code 输出内容: 开始执行线程... 5秒后准备唤醒线程.. 结束执行线程... Process finished with exit code 0 注意以下几点: 1)当线程T1被notify过后,也必须要重新获取对象锁,才能够继续执行 2)sleep也能达到wait的效果,但是唯一区别时,sleep时并不会释放对象锁,因此其他线程并没有得到执行的机会

优秀的个人博客,低调大师

java中的单元测试Junit4

首先就是主要简单的讲一下Junit的使用,属于傻瓜式速成教程,gogogogogogogo! 一:什么是单元测试: 我们在编写大型程序的时候,需要写成千上万个方法或函数,这些函数的功能可能很强大,但我们在程序中只用到该函数的一小部分功能,并且经过调试可以确定,这一小部分功能是正确的。但是,我们同时应该确保每一个函数都完全正确,因为如果我们今后如果对程序进行扩展,用到了某个函数的其他功能,而这个功能有bug的话,那绝对是一件非常郁闷的事情。所以说,每编写完一个函数之后,都应该对这个函数的方方面面进行测试,这样的测试我们称之为单元测试。传统的编程方式,进行单元测试是一件很麻烦的事情,你要重新写另外一个程序,在该程序中调用你需要测试的方法,并且仔细观察运行结果,看看是否有错。这样的话太过于麻烦了,本文简要介绍一下在Eclipse中使用JUnit4进行单元测试的方法。用更加通俗的话来描述单元测试就是:写了个类,要给别人用,会不会有bug?怎么办?测试一下。用main方法测试好不好?这种方法我们经常用,就是写一个方法实现一些功能,把方法的调用方式放在main函数中。这样的测试方式一个是使得main函数太过于混乱,再者测试过程需要人的仔细观察来辨别每个函数的功能实现,哪一个函数出错了,哪一个函数没有输出之类的问题层出不穷,单元测试就是来解决这些问题的。下面我会就单元测试的每一步给出详细的图解和描述。 二:进行单元测试: 首先我先创建一个就是一个简单的计算机类,里面就写一个加除的方法; 1 package junit; 2 3 public class Reckon {//一个计算类 4 5 //简单的实现两个计算方法 6 public int add(int num1,int num2){ 7 return num1+num2; 8 } 9 10 public int divide(int num1,int num2){ 11 return num1/num2; 12 } 13 14 public static void main(String[] args) { 15 //传统的把方法的调用方式放在main函数中测试运行 16 int num=new Reckon().add(1, 2); 17 System.out.println(num); 18 } 19 } 下面进行单元测试: 右键新建:选择junit Test Case 接着next,出现下面的画面,用junit4,在下面选择要测试的类,给这个测试类起一个名字。 点击next出现下面的画面,这是选择要测试的方法; 点击finish,添加jar包; 这一步提示我们是否将我们需要的JUnit 4的相关包加入到我们项目的ClassPath路径下,点击OK就行,因为Eclipse中包含JUnit的jar包。 做完上面的会自动生成这样一个测试类; 1 package junit; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.Test; 6 7 public class Reckon_Test { 8 9 @Test 10 public void testAdd() { 11 fail("Not yet implemented"); 12 } 13 14 @Test 15 public void testDivide() { 16 fail("Not yet implemented"); 17 } 18 19 } Test注解表示这是个测试方法; 修改里面的方法: 1 package junit; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.Test; 6 7 public class Reckon_Test { 8 9 @Test 10 public void testAdd() { 11 int z=new Reckon().add(2, 8); 12 assertEquals(10,z);//判断得到的z是不是10也就是正确的答案 13 } 14 15 @Test 16 public void testDivide() { 17 int z=new Reckon().divide(8, 2); 18 System.out.println(z); 19 } 20 21 } 右键选择Junit Test 运行 绿色代表测试成功,其中Error:程序出错 Failures:测试失败 如果我们把除数修改为零,则会出现数学异常 常用的方法: 欢迎大家一起说出自己的想法。

优秀的个人博客,低调大师

JAVA 并发编程学习(1)之基本概念

1,为什么需要并发? 在早期计算机中没有操作系统,一台计算机从头到尾只执行一个程序,如果这个程序的任务是先进行CPU计算再把计算结果写入文件。那么,在进行CPU计算时,这台计算机的IO模块是空闲的,把计算结果写入文件中时,这台计算机的CPU是空闲的。 为此,引入了操作系统。这样,在一台计算机中可以运行多个程序了。由操作系统来管理多个程序的运行,一个程序在进行CPU计算的同时,另一个程序可以进行IO操作。提高了计算机的利用率(CPU和IO操作 可以同时在发生了) 引入操作系统之后,不可避免地出现了进程这个概念。因为操作系统管理若干个程序了,而每个运行中的程序可以用进程来表示(进程的动态性)。 那为什么还需要线程呢? ①进程之间需要通信、需要共享一些数据,需要协作……这些用线程来“表示”更方便。因为,不同进程的地址空间是相互独立的,一个进程不能直接访问另一个进程的地址空间。一个进程内部的多个线程共享这个进程状态空间,如果把数据的共享放到线程这个层次来实现,就方便多了。 ②进一步提高资源利用率---这个有点类似于:从没有操作系统的计算机到有操作系统的计算机转变---这里是从没有线程到有线程转变。 2,我们就是因为方便数据共享……一些原因引入了线程,那么多个线程同时访问一个可变的变量时,这个变量到底处理哪一个状态?这就存在一种线程安全性问题。 3,什么是线程安全性 讨论线程安全性针对的是 类。核心就是正确性。即,某个类的行为和其规范完全一致:即,我写了一个类,这个类具有哪些功能,需要完成哪些操作……这些是类的规范;而多个线程运行这个类的代码时,其执行效果和规范描述的要一致。 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全的。 4,无状态对象 5,Race Condition 竞态条件 ①读--修改--写入 ②check--then--act 本文转自hapjin博客园博客,原文链接:http://www.cnblogs.com/hapjin/,如需转载请自行联系原作者

优秀的个人博客,低调大师

分析一种前缀树的java实现

private class TrieNode{ /** * 标识当前结点是否是一个“关键词”的最后一个结点 * true 关键词的终结 false 继续 */ private boolean isEnd = false; /** * 用map来存储当前结点的所有子节点,非常的方便 * key 下一个字符 value 对应的结点 */ private Map<Character , TrieNode> subNodes = new HashMap<>(); /** * 向指定位置添加结点树 * @param key * @param node */ public void addSubNode(Character key , TrieNode node){ subNodes.put(key , node); } /** * 根据key获得相应的子节点 * @param key * @return */ public TrieNode getSubNode(Character key){ return subNodes.get(key); } //判断是否是关键字的结尾 public boolean isKeyWordEnd(){ return isEnd; } //设置为关键字的结尾 public void setKeyWordEnd(boolean isEnd){ this.isEnd = isEnd; } } /** * 核心算法一:构建字典树 * 根据输入的字符串,逐步构建字典树 * @param textLine */ private void addDirTreeNode(String textLine){ //边界处理 if(textLine == null) return; //临时结点指向根结点 TrieNode tempNode = root; for(int i = 0; i < textLine.length(); i++){ char charWord = textLine.charAt(i); //直接跳过非法文字 if (isSymbol(charWord)) continue; TrieNode node = tempNode.getSubNode(charWord); if (node == null){ //说明tempNode第一次碰到该关键字结点 node = new TrieNode(); tempNode.addSubNode(charWord , node); } //tempNode指向下一个结点,开始下一次循环 tempNode = node; //到敏感词的最后一个字时,标记为红色(关键词结尾) if (i == textLine.length() - 1) tempNode.setKeyWordEnd(true); } }

优秀的个人博客,低调大师

CentOS 7.4 java验证码乱码的问题

新服务器配置发布网站 配置后程序顺利启动在登录时发现验证码无法识别显示出了图片,但是字是乱码 初步估计应该是字体问题 ssh登录服务器查看默认字体 #fc-match msam10.ttf: "msam10" "LyX"确认是字体问题 解决字体问题 1. 从windows系统拷贝 微软雅黑字体 打开文件夹 C:WindowsFonts选中微软雅黑字体,复制拷贝到别的文件夹 2. 将字体文件上传到centos服务器 #mkdir /usr/local/font/default将字体文件上传到default目录中 3.更新字体缓存 #fc-cache 4.再次查看默认字体 #fc-match msyh.ttc: "Microsoft YaHei" "Normal"字体正确 5.重启tomcat #systemctl restart tomcat重启之后 验证码显示正确。

优秀的个人博客,低调大师

16.4. jstat - Java Virtual Machine Statistics Monitoring Tool

# jstat -class 15888 1000 10 Loaded Bytes Unloaded Bytes Time 17409 34782.5 231 339.0 13.21 17409 34782.5 231 339.0 13.21 17409 34782.5 231 339.0 13.21 17409 34782.5 231 339.0 13.21 17409 34782.5 231 339.0 13.21 17409 34782.5 231 339.0 13.21 # jstat -gc 15888 1000 10 S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 13824.0 13824.0 1204.1 0.0 2766848.0 2327059.3 349696.0 318073.6 229888.0 101912.6 288 4.895 2 1.055 5.949 13824.0 13824.0 1204.1 0.0 2766848.0 2327059.3 349696.0 318073.6 229888.0 101912.6 288 4.895 2 1.055 5.949 13824.0 13824.0 1204.1 0.0 2766848.0 2327059.3 349696.0 318073.6 229888.0 101912.6 288 4.895 2 1.055 5.949 13824.0 13824.0 1204.1 0.0 2766848.0 2327059.3 349696.0 318073.6 229888.0 101912.6 288 4.895 2 1.055 5.949 # jstat -gcutil 15888 S0 S1 E O P YGC YGCT FGC FGCT GCT 8.71 0.00 84.12 90.96 44.33 288 4.895 2 1.055 5.949 # jstat -compiler 15888 Compiled Failed Invalid Time FailedType FailedMethod 2987 0 0 59.55 0 # jstat -gccapacity 15888 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC 175104.0 2796544.0 2794496.0 13824.0 13824.0 2766848.0 349696.0 5592064.0 349696.0 349696.0 65536.0 524288.0 229888.0 229888.0 288 2 # jstat -gcnew 15888 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 13824.0 13824.0 1204.1 0.0 1 15 13824.0 2766848.0 2327429.8 288 4.895 # jstat -gcnewcapacity 15888 NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC 175104.0 2796544.0 2794496.0 931840.0 13824.0 931840.0 13824.0 2795520.0 2766848.0 288 2 # jstat -gcold 15888 PC PU OC OU YGC FGC FGCT GCT 229888.0 101912.6 349696.0 318073.6 288 2 1.055 5.949 # jstat -gcoldcapacity 15888 OGCMN OGCMX OGC OC YGC FGC FGCT GCT 349696.0 5592064.0 349696.0 349696.0 288 2 1.055 5.949 每 1000 毫秒打印一次,一共打印 5 次,还可以加上 -h3 每三行显示一下标题。 # jstat -printcompilation -h3 15888 Compiled Size Type Method 2987 91 1 org/apache/catalina/connector/Request isAlpha 原文出处:Netkiller 系列 手札 本文作者:陈景峯 转载请与作者联系,同时请务必标明文章原始出处和作者信息及本声明。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册