一、Dubbo是什么? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC(一种远程调用) 分布式服务框架(SOA),致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。 二、为什么要用Dubbo? 因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。
1 2 3 |
1、使用Dubbo可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用 灵活扩展,使前端应用能更快速的响应多变的市场需求。 2、分布式架构可以承受更大规模的并发流量。 |
三、Dubbo 和 Spring Cloud 有什么区别?
1 2 3 4 5 |
1、通信方式不同:Dubbo 使用的是 RPC 通信,而Spring Cloud 使用的是HTTP RESTFul 方式。 2、组成不一样: dubbo的服务注册中心为Zookeerper,服务监控中心为dubbo-monitor,无消息总线,服务跟踪、批量任务等组件; spring-cloud的服务注册中心为spring-cloud netflix enruka,服务监控中心为spring-boot admin,有消息总线,数据流、服务跟踪、批量任务等组件; 四、Dubbo需要 Web 容器吗? |
不需要,如果硬要用Web 容器,只会增加复杂性,也浪费资源。 五、Dubbo内置了哪几种服务容器?
1 2 3 4 |
三种服务容器: 1、Spring Container 2、Jetty Container 3、Log4j Container |
Dubbo 的服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。 六、dubbo都支持什么协议,推荐用哪种?
1 2 3 4 5 |
1、dubbo://(推荐) 2、http:// 3、rest:// 4、redis:// 5、memcached:// |
七、Dubbo里面有哪几种节点角色?
1 2 3 4 5 |
1、provide:暴露服务的服务提供方 2、consumer:调用远程服务的服务消费方 3、registry:服务注册于发现的注册中心 4、monitor:统计服务调用次数和调用时间的监控中心 5、container:服务运行容器 |
八、dubbo服务注册与发现的流程图 dubbo服务注册与发现的流程图 九、Dubbo默认使用什么注册中心,还有别的选择吗? 推荐使用zookeeper作为注册中心,还有redis、multicast、simple注册中心。 十、Dubbo 核心的配置有哪些? Dubbo 核心的配置 十一、在 Provider 上可以配置的 Consumer 端的属性有哪些?
1 2 3 4 |
1、timeout:方法调用超时 2、retries:失败重试次数,默认重试 2 次 3、loadbalance:负载均衡算法,默认随机 4、actives 消费者端,最大并发调用限制 |
十二、Dubbo有哪几种负载均衡策略,默认是哪种?
1 2 3 4 |
1、random loadbalance:安权重设置随机概率(默认); 2、roundrobin loadbalance:轮寻,按照公约后权重设置轮训比例; 3、lastactive loadbalance:最少活跃调用数,若相同则随机; 4、consistenthash loadbalance:一致性hash,相同参数的请求总是发送到同一提供者。 |
十三、Dubbo启动时如果依赖的服务不可用会怎样? Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。 十四、Dubbo推荐使用什么序列化框架,你知道的还有哪些?
1 |
推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化; |
十五、Dubbo默认使用的是什么通信框架,还有别的选择吗?
1 |
Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。 |
十六、Dubbo有哪几种集群容错方案,默认是哪种? Dubbo集群容错方案 十七、服务提供者能实现失效踢出是什么原理?
1 |
服务失效踢出基于zookeeper的临时节点原理。 |
十八、Dubbo服务之间的调用是阻塞的吗?
1 2 3 |
默认是同步等待结果阻塞的,支持异步调用。 Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对 多线程开销较小,异步调用会返回一个 Future 对象。 |
Dubbo暂时不支持分布式事务。 十九、Dubbo的管理控制台能做什么?
1 2 |
管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。 注:dubbo源码中的dubbo-admin模块打成war包,发布运行即可得到dubbo控制管理界面。 |
二十、Dubbo 服务暴露的过程
1 2 3 4 |
Dubbo 会在 Spring 实例化完 bean 之后,在刷新容器最后一步发布 ContextRefreshEvent 事件的时候,通知 实现了 ApplicationListener 的 ServiceBean 类进行回调 onApplicationEvent 事件方法,Dubbo 会在这个方法 中调用 ServiceBean 父类 ServiceConfig 的 export 方法,而该方法真正实现了服务的(异步或者非异步)发 布。 |
二十一、当一个服务接口有多种实现时怎么做? 当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group […]
View Details直接上代码了。 Java控制台代码: package Test; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.codec.binary.Base64; public class Test { private static final String encoding = "UTF-8"; public static void main(String[] args) { try { String text = "20200121";// 明文 String key = "Tt3rLPrDIVIhXqAz";// 长度控制为16,作为3DES加密用的key String encryptStr = EncryptData(text, key);// 3DES加密结果 System.out.println("明文:" + text); System.out.println("密钥:" + key); System.out.println("密文:" + encryptStr); System.out.println("解密:" + DecryptData(encryptStr, key)); } catch (Exception e) { e.printStackTrace(); } } /** * DESede加密,key长度为16 * * @param plainText 明文 * @param key 密钥 * @return DESede加密结果 * […]
View Details1.使用jdk自带的webservice工具wsimport生成相关类 测试wsdl http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl
1 |
wsimport -s d:\wsdl -p com.example.demo.request -encoding utf-8 http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl |
-s 存储目录; -p 包名; -encoding 文件编码,默认会采用操作系统编码,中文为gbk,建议使用utf-8; 2.构建相关的配置类及测试方法
1 2 3 4 5 6 7 8 |
@Configuration public class IpConfig { @Bean public IpAddressSearchWebServiceSoap webService(){ return new IpAddressSearchWebService().getIpAddressSearchWebServiceSoap(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@SpringBootApplication @RestController @RequestMapping("/soap") public class DemoApplication { @Autowired private IpAddressSearchWebServiceSoap soap; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @RequestMapping("/{ip}") public ArrayOfString searchIp(@PathVariable("ip") String ip) { ArrayOfString response = soap.getCountryCityByIp(ip); return response; } } |
from:https://blog.csdn.net/VitaminZH/article/details/81123571
View Details我们是否一样? 估计很多小伙伴(也包括我自己)都有这种情况,在自学Java语言看书时,关于枚举enum这一块的知识点可能都有点 “轻敌” ,觉得这块内容非常简单,一带而过,而且在实际写代码过程中也不注意运用。 是的,我也是这样!直到有一天我提的代码审核没过,被技术总监一顿批,我才重新拿起了《Java编程思想》,把枚举这块的知识点重新又审视了一遍。 为什么需要枚举 常量定义它不香吗?为啥非得用枚举? 举个栗子,就以B站上传视频为例,视频一般有三个状态:草稿、审核和发布,我们可以将其定义为静态常量:
1 2 3 4 5 6 7 8 |
public class VideoStatus { public static final int Draft = 1; //草稿 public static final int Review = 2; //审核 public static final int Published = 3; //发布 } |
对于这种单值类型的静态常量定义,本身也没错,主要是在使用的地方没有一个明确性的约束而已,比如:
1 2 3 4 5 |
void judgeVideoStatus( int status ) { ... } |
比如这里的 judgeVideoStatus 函数的本意是传入 VideoStatus 的三种静态常量之一,但由于没有类型上的约束,因此传入任意一个int值都是可以的,编译器也不会提出任何警告。 但是在枚举类型出现之后,上面这种情况就可以用枚举严谨地去约束,比如用枚举去定义视频状态就非常简洁了:
1 2 3 |
public enum VideoStatus { Draft, Review, Published } |
而且主要是在用枚举的地方会有更强的类型约束:
1 2 3 4 5 6 |
// 入参就有明确类型约束 void judgeVideoStatus( VideoStatus status ) { ... } |
这样在使用 judgeVideoStatus 函数时,入参类型就会受到明确的类型约束,一旦传入无效值,编译器就会帮我们检查,从而规避潜在问题。 除此之外,枚举在扩展性方面比普常量更方便、也更优雅。 重新系统认识一下枚举 还是拿前文《答应我,别再if/else走天下了可以吗》中的那个例子来说:比如,在后台管理系统中,肯定有用户角色一说,而且角色一般都是固定的,适合定义成一个枚举:
1 2 3 4 5 6 7 8 |
public enum UserRole { ROLE_ROOT_ADMIN, // 系统管理员 ROLE_ORDER_ADMIN, // 订单管理员 ROLE_NORMAL // 普通用户 } |
接下来我们就用这个UserRole为例来说明枚举的所有基本用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
UserRole role1 = UserRole.ROLE_ROOT_ADMIN; UserRole role2 = UserRole.ROLE_ORDER_ADMIN; UserRole role3 = UserRole.ROLE_NORMAL; // values()方法:返回所有枚举常量的数组集合 for ( UserRole role : UserRole.values() ) { System.out.println(role); } // 打印: // ROLE_ROOT_ADMIN // ROLE_ORDER_ADMIN // ROLE_NORMAL // ordinal()方法:返回枚举常量的序数,注意从0开始 System.out.println( role1.ordinal() ); // 打印0 System.out.println( role2.ordinal() ); // 打印1 System.out.println( role3.ordinal() ); // 打印2 // compareTo()方法:枚举常量间的比较 System.out.println( role1.compareTo(role2) ); //打印-1 System.out.println( role2.compareTo(role3) ); //打印-2 System.out.println( role1.compareTo(role3) ); //打印-2 // name()方法:获得枚举常量的名称 System.out.println( role1.name() ); // 打印ROLE_ROOT_ADMIN System.out.println( role2.name() ); // 打印ROLE_ORDER_ADMIN System.out.println( role3.name() ); // 打印ROLE_NORMAL // valueOf()方法:返回指定名称的枚举常量 System.out.println( UserRole.valueOf( "ROLE_ROOT_ADMIN" ) ); System.out.println( UserRole.valueOf( "ROLE_ORDER_ADMIN" ) ); System.out.println( UserRole.valueOf( "ROLE_NORMAL" ) ); |
除此之外,枚举还可以用于switch语句中,而且意义更加明确:
1 2 3 4 5 6 7 8 9 10 11 12 |
UserRole userRole = UserRole.ROLE_ORDER_ADMIN; switch (userRole) { case ROLE_ROOT_ADMIN: // 比如此处的意义就非常清晰了,比1,2,3这种数字好! System.out.println("这是系统管理员角色"); break; case ROLE_ORDER_ADMIN: System.out.println("这是订单管理员角色"); break; case ROLE_NORMAL: System.out.println("这是普通用户角色"); break; } |
自定义扩充枚举 上面展示的枚举例子非常简单,仅仅是单值的情形,而实际项目中用枚举往往是多值用法。 比如,我想扩充一下上面的UserRole枚举,在里面加入 角色名 — 角色编码 的对应关系,这也是实际项目中常用的用法。 这时候我们可以在枚举里自定义各种属性、构造函数、甚至各种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public enum UserRole { ROLE_ROOT_ADMIN( "系统管理员", 000000 ), ROLE_ORDER_ADMIN( "订单管理员", 100000 ), ROLE_NORMAL( "普通用户", 200000 ), ; // 以下为自定义属性 private final String roleName; //角色名称 private final Integer roleCode; //角色编码 // 以下为自定义构造函数 UserRole( String roleName, Integer roleCode ) { this.roleName = roleName; this.roleCode = roleCode; } // 以下为自定义方法 public String getRoleName() { return this.roleName; } public Integer getRoleCode() { return this.roleCode; } public static Integer getRoleCodeByRoleName( String roleName ) { for( UserRole enums : UserRole.values() ) { if( enums.getRoleName().equals( roleName ) ) { return enums.getRoleCode(); } } return null; } } |
从上述代码可知,在enum枚举类中完全可以像在普通Class里一样声明属性、构造函数以及成员方法。 枚举 + 接口 = ? 比如在我的前文《答应我,别再if/else走天下了可以吗》中讲烦人的if/else消除时,就讲过如何通过让枚举去实现接口来方便的完成。 这地方不妨再回顾一遍: 什么角色能干什么事,这很明显有一个对应关系,所以我们首先定义一个公用的接口RoleOperation,表示不同角色所能做的操作:
1 2 3 |
public interface RoleOperation { String op(); // 表示某个角色可以做哪些op操作 } |
接下来我们将不同角色的情况全部交由枚举类来做,定义一个枚举类RoleEnum,并让它去实现RoleOperation接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public enum RoleEnum implements RoleOperation { // 系统管理员(有A操作权限) ROLE_ROOT_ADMIN { @Override public String op() { return "ROLE_ROOT_ADMIN:" + " has AAA permission"; } }, // 订单管理员(有B操作权限) ROLE_ORDER_ADMIN { @Override public String op() { return "ROLE_ORDER_ADMIN:" + " has BBB permission"; } }, // 普通用户(有C操作权限) ROLE_NORMAL { @Override public String op() { return "ROLE_NORMAL:" + " has CCC permission"; } }; } |
这样,在调用处就变得异常简单了,一行代码就行了,根本不需要什么if/else:
1 2 3 4 5 6 |
public class JudgeRole { public String judge( String roleName ) { // 一行代码搞定!之前的if/else灰飞烟灭 return RoleEnum.valueOf(roleName).op(); } } |
而且这样一来,以后假如我想扩充条件,只需要去枚举类中加代码即可,而不用改任何老代码,非常符合开闭原则! 枚举与设计模式 什么?枚举还能实现设计模式? 是的!不仅能而且还能实现好几种! 1、单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class Singleton { // 构造函数私有化,避免外部创建实例 private Singleton() { } //定义一个内部枚举 public enum SingletonEnum{ SEED; // 唯一一个枚举对象,我们称它为“种子选手”! private Singleton singleton; SingletonEnum(){ singleton = new Singleton(); //真正的对象创建隐蔽在此! } public Singleton getInstnce(){ return singleton; } } // 故意外露的对象获取方法,也是外面获取实例的唯一入口 public static Singleton getInstance(){ return SingletonEnum.SEED.getInstnce(); // 通过枚举的种子选手来完成 } } |
2、策略模式 这个也比较好举例,比如用枚举就可以写出一个基于策略模式的加减乘除计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public class Test { public enum Calculator { ADDITION { public Double execute( Double x, Double y ) { return x + y; // 加法 } }, SUBTRACTION { public Double execute( Double x, Double y ) { return x - y; // 减法 } }, MULTIPLICATION { public Double execute( Double x, Double y ) { return x * y; // 乘法 } }, DIVISION { public Double execute( Double x, Double y ) { return x/y; // 除法 } }; public abstract Double execute(Double x, Double y); } public static void main(String[] args) { System.out.println( Calculator.ADDITION.execute( 4.0, 2.0 ) ); // 打印 6.0 System.out.println( Calculator.SUBTRACTION.execute( 4.0, 2.0 ) ); // 打印 2.0 System.out.println( Calculator.MULTIPLICATION.execute( 4.0, 2.0 ) ); // 打印 8.0 System.out.println( Calculator.DIVISION.execute( 4.0, 2.0 ) ); // 打印 2.0 } } |
专门用于枚举的集合类 我们平常一般习惯于使用诸如:HashMap 和 HashSet等集合来盛放元素,而对于枚举,有它专门的集合类:EnumSet和EnumMap 1、EnumSet EnumSet 是专门为盛放枚举类型所设计的 Set 类型。 还是举例来说,就以文中开头定义的角色枚举为例:
1 2 3 4 5 6 7 8 |
public enum UserRole { ROLE_ROOT_ADMIN, // 系统管理员 ROLE_ORDER_ADMIN, // 订单管理员 ROLE_NORMAL // 普通用户 } |
比如系统里来了一批人,我们需要查看他是不是某个角色中的一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 定义一个管理员角色的专属集合 EnumSet<UserRole> userRolesForAdmin = EnumSet.of( UserRole.ROLE_ROOT_ADMIN, UserRole.ROLE_ORDER_ADMIN ); // 判断某个进来的用户是不是管理员 Boolean isAdmin( User user ) { if( userRoles.contains( user.getUserRole() ) ) return true; return false; } |
2、EnumMap 同样,EnumMap 则是用来专门盛放枚举类型为key的 Map 类型。 比如,系统里来了一批人,我们需要统计不同的角色到底有多少人这种的话:
1 2 3 4 5 6 7 8 9 10 |
Map<UserRole,Integer> userStatisticMap = new EnumMap<>(UserRole.class); for ( User user : userList ) { Integer num = userStatisticMap.get( user.getUserRole() ); if( null != num ) { userStatisticMap.put( user.getUserRole(), num+1 ); } else { userStatisticMap.put( user.getUserRole(), 1 ); } } |
用EnumMap可以说非常方便了。 总 结 小小的枚举就玩出这么多的花样,不过好在探索和总结的过程还挺有意思的,也复习了很多知识,慢慢来吧。 from:https://my.oschina.net/hansonwang99/blog/3196498
View Detailswindows: set java_home:查看JDK安装路径 java -version:查看JDK版本 linux: whereis java which java (java执行路径) echo $JAVA_HOME echo $PATH from:https://blog.csdn.net/Xin7Xin/article/details/86304542
View Detailsbytes[] 到数字类型的转换是个经常用到的代码,解决方式也不止一种,最近需要将bytes[]转为long,有机会深入了解了一下,此文做个总结。 java代码实现 如果不想借助任何已经有的类,完全可以自己实现这段代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ long value=0; // 循环读取每个字节通过移位运算完成long的8个字节拼装 for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } |
借助java.nio.ByteBuffer实现 java.nio.ByteBuffer 本身就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就可以实现所有primitive类型的数据读取,参见javadoc。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { // 将byte[] 封装为 ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } |
借助java.io.DataInputStream实现 java.io.DataInputStream 同样提供了readLong,readLong,readLong….方法,只要将byte[]转换为DataInputStream就可以实现所有primitive类型的数据读取,参见javadoc。 完整测试代码 下面的Junit 测试代码计算String 的MD5校验码(16 bytes),然后使用上述方式分别将16 bytes转换为2个long(大端模式)然后以16进制模式输出结果,以验证三种方式一致性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
package net.gdface.facelog; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.junit.Test; public class TestSerialVersionUID { /** * 生成MD5校验码 * * @param source * @return */ static public byte[] getMD5(byte[] source) { if (null==source) return null; try { MessageDigest md = MessageDigest.getInstance("MD5"); return md.digest(source); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 将16位byte[] 转换为32位的HEX格式的字符串String * * @param buffer * @return */ static public String toHex(byte buffer[]) { if (null==buffer) return null; StringBuffer sb = new StringBuffer(buffer.length * 2); for (int i = 0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16)); sb.append(Character.forDigit(buffer[i] & 15, 16)); } return sb.toString(); } /** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); long value=0; for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } /** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } @Test public void test() throws IOException { String input="net.gdface.facelog.dborm.person.FlPersonBeanBase"; byte[] md5 = getMD5(input.getBytes()); System.out.printf("md5 [%s]\n",toHex(md5)); // 三种方式运算结果对比验证 DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(md5)); long l1 = dataInput.readLong(); long l2 = dataInput.readLong(); System.out.printf("l1=0x%x l2=0x%x,DataInputStream\n", l1,l2); long ln1 = bytesToLong(md5,0, false); long ln2 = bytesToLong(md5,8, false); System.out.printf("ln1=0x%x ln2=0x%x,ByteBuffer\n", ln1,ln2); long ll1 = longFrom8Bytes(md5,0, false); long ll2 = longFrom8Bytes(md5,8, false); System.out.printf("ll1=0x%x ll2=0x%x\n", ll1,ll2); } } |
输出结果 md5 [39627933ceeebf2740e1f822921f5837] l1=0x39627933ceeebf27 l2=0x40e1f822921f5837,DataInputStream ln1=0x39627933ceeebf27 ln2=0x40e1f822921f5837,,ByteBuffer ll1=0x39627933ceeebf27 ll2=0x40e1f822921f5837 参考资料 《Java 中 byte、byte 数组和 int、long 之间的转换》 from:https://blog.csdn.net/10km/article/details/77435659
View Details第一种:饿汉模式(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Single2 { private static Single2 instance = new Single2(); private Single2(){ System.out.println("Single2: " + System.nanoTime()); } public static Single2 getInstance(){ return instance; } } |
第二种:懒汉模式 (如果方法没有synchronized,则线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Single3 { private static Single3 instance = null; private Single3(){ System.out.println("Single3: " + System.nanoTime()); } public static synchronized Single3 getInstance(){ if(instance == null){ instance = new Single3(); } return instance; } } |
第三种:懒汉模式改良版(线程安全,使用了double-check,即check-加锁-check,目的是为了减少同步的开销)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Single4 { private volatile static Single4 instance = null; private Single4(){ System.out.println("Single4: " + System.nanoTime()); } public static Single4 getInstance(){ if(instance == null){ synchronized (Single4.class) { if(instance == null){ instance = new Single4(); } } } return instance; } } |
第四种:利用私有的内部工厂类(线程安全,内部类也可以换成内部接口,不过工厂类变量的作用域要改为public了。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Singleton { private Singleton(){ System.out.println("Singleton: " + System.nanoTime()); } public static Singleton getInstance(){ return SingletonFactory.singletonInstance; } private static class SingletonFactory{ private static Singleton singletonInstance = new Singleton(); } } |
from:https://my.oschina.net/yangchunlian/blog/1607947
View Details在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。请参考答案中的示例代码。 【生产者】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Producer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Producer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 生产数据 for (int i = 0; i < 7; i++) { System.out.println("Produced:" + i); try { produce(i); } catch (InterruptedException ex) { Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); } } } private void produce(int i) throws InterruptedException { // wait if queue is full while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } // producing element and notify consumers synchronized (sharedQueue) { sharedQueue.add(i); sharedQueue.notifyAll(); } } } |
【消费者】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Consumer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Consumer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 消费数据 while (true) { try { System.out.println("Consumer: " + consume()); Thread.sleep(50); } catch (InterruptedException ex) { Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); } } } private int consume() throws InterruptedException { // wait if queue is empty while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } //otherwise consume element and notify waiting producer synchronized (sharedQueue) { sharedQueue.notifyAll(); return (Integer) sharedQueue.remove(0); } } } |
【测试函数】
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.Vector; public class ProducerConsumerSolution { public static void main(String[] args) { Vector sharedQueue = new Vector(); int size = 4; Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer"); Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer"); prodThread.start(); consThread.start(); } } |
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Produced:0 Queue is empty Consumer is waiting , size: 0 Produced:1 Consumer: 0 Produced:2 Produced:3 Produced:4 Produced:5 Queue is full Producer is waiting , size: 4 Consumer: 1 Produced:6 Queue is full Producer is waiting , size: 4 Consumer: 2 Consumer: 3 Consumer: 4 Consumer: 5 Consumer: 6 Queue is empty Consumer is waiting , size: 0 |
from:https://www.cnblogs.com/xbq8080/p/10371214.html
View Details事故现场: 解决办法: 一是命令行,
1 |
mvn clean package -Dmaven.test.skip=true |
二是写入pom文件
1 2 3 4 5 6 7 8 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> |
from:https://www.cnblogs.com/lxcy/p/8279899.html
View Details1.git 项目到仓库中。 2.运行maven 导入JAR包 3.配置项目project structure(CTRL+ALT+SHIFT+S) project settings 第一项 Project compiler output 路径 : D:\git\CMS\target\shishuocms-2.0.1\WEB-INF\classes 第二项 Modules: Paths 选择第一个 Inherit project compile output path 复制 applicationContext.xml 、 log4j.properties、 shishuocms.properties 到 target/shishuocms-2.0.1/WEB-INF/classes下面。 别忘了修改shishuocms.properties的数据库连接配置。 ———————————————— 版权声明:本文为CSDN博主「matt0614」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/matt0614/article/details/44972539
View Details