• [技术干货] java之character类
    character类用于对单个字符进行操作character类在对象中包装一个基本类型char的值char ch ='a'char unichar='\u039a'CHAR[]charArray={‘a’,‘b’,‘c’}然而 在实际开发过程中我们经常会遇到需要使用对象而不是内置数据类型的情况 为了解决这个entire java语言在内置数据类型char提供了包装character类character ch=new character('a')在一些情况下 java编译器会自动创建一个character对象例如:将一个char类参数传递给需要一个character类型参数的方法时  那么编译器会自动的将char类型参数转换为character的的对象这种特征叫做封箱 反过来叫拆箱原始值a 封装到character提供的对象中的方法ch中  即:character ch ='a'char  c =test('x');转义序列前有反斜杠(\)的字符代表转义字符 它对编译器来说是有特殊含义的下面列表展示了java 的转义序列。常用的有:\t  在文中国插入一个tab  \b在文中插入一个后退键 \n在文中该处换行\r在文中该处插入回车\f在文中该处插入换页符\'在文中该处插入单引导\''在文章该处插入双引导\\在文章该处插入反斜杠例如:System.out.println("访问\"huaweilll!\"")character 方法is letter() 是否是一个字母is digit 是否是一个数字字符iswhilespace 是一个空白字符is uppercase  是否是大写字母is lowercase  指定字母的小写形式tostring()返回字符的字符串形式字符串的长度仅为1、结束!
  • [技术干货] java之scanner类
    java util scanner 是java5的新的特征我们可以通过scanner类来获取用户的输入。如何创建scanner对象的基本语法呢?scanner  s =new scanner(system.in);接下来我们演示一个最简单的数据输入,并通过scanner类的net()和nextline()方法获取输入的字符串  在读取我们一般需要使用 hasnext和hasnextline判断是否还有输入的数据如何使用next方法呢?接下来我们接受nextline方法:上述代码中明显阐述了二者的区别next1:一定要读到有效字符后才可以结束输入2:对输入有效字符制器遇到的空白 next()方法会自动将其去掉3:只有输入有效字符后才将其后面输入的空白作为分割符或者结束符next()不能得到带有空格的字符串 nextline()可以获得空白以enter为结束符也就是说nextline()方法返回的是输入回车之前的所有字符如果要输入int或float类的数据 在scanner类中也有支持 但是在输入之前最好先使用has nextXXX()方法进行验证在使用nextXXX()方法来读取练习个例子 今天就到此结束吧  咯咯咯
  • [技术干货] java条件语句之 if-else
    一个if语句包含一个布尔表达式和一条或多条的语句语法:if语句的语法如下if(布尔表达式的值){//如果布尔表达式为true 将执行的语句}结果:如果布尔表达式的值为true  则执行if语句中的代码否则跳过if执行if后面语句的代码例如:if...else 语句  if语句后面可以跟else语句 当if语句的布尔表达式值为false时 else语句块会被执行语法:  if(布尔表达式值){//是布尔表达式的值为true}else{是布尔表达式的值为false}if..else  if..else语句if语句后面可以跟else  if  else  这种语句可以检查到多种可能的情况 使用if  else  if else语句的时候 需要注意以下几点if语句之多有一个else语句 else语句在所有的elseif之后 if语句可以有若干个else if 语句 比在在else之前一旦其中一个else if语句检查为true 其他的elseif以及else语句都将跳过执行就近原则 判断if和else相邻语法: if(布尔表达式 1){ //如果布尔表达式 1的值为true执行代码 }else if(布尔表达式 2){ //如果布尔表达式 2的值为true执行代码 }else if(布尔表达式 3){ //如果布尔表达式 3的值为true执行代码 }else { //如果以上布尔表达式都不为true执行代码 }嵌套的if else 语句 使用嵌套的if else语句是合法的 也就是说可以在另一个if或者else if语句中使用if或者else if语句语法: if(布尔表达式1){ 布尔表达式1为true执行的代码          if(布尔表达式2){布尔表达式2为true执行的代码}}你可以像if语句一样嵌套else  if..else实例:到这里 ifelse 的语句就结束了 感谢大家阅读  喜欢的话记得点赞+收藏哦!
  • [技术干货] java第六期之 基本数据类型
    java循环结构和其他语言类似  包括 for  while  和do while顺序结构的程序语句只能被执行一次 如果想执行同样的操作多次就需要使用循环结构for循环是从java5中引入的主要用于数组while循环   while循环是基本的循环 结构为while(布尔表达式的值){   //循环内容}只要boolean表达式为真就会一直循环下去  例如: int x = 10; while( x < 20 ) { System.out.print("value of x : " + x ); x++; System.out.print("\n");}结果会以10为初始值 每次步进为1的递增 直到 while中的布尔值为false时跳出循环do while 循环对于while语言而将 如果不满足条件则不能进入循环 但有时候我们需要即使不满足条件也要至少执行一次  do while 循环和while 循环类似  不同的是 do while 循环至少循环一次基本结构: do { //代码}while(布尔表达式的值);注意:布尔表达式在循环体的后面 所以语句在检测布尔表达式之前就已经执行了如果布尔表达式的值为true  则语句快将一直执行下去 直到布尔表达式的值为假例如int x = 100;do{ System.out.print("value of x : " + x ); x++; System.out.print("\n");}while( x < 220 );结果会以100为初值 +1为步进当不满足布尔表达式时跳出循环 且至少循环一次for循环 虽然所有循环结构都可以用while  dowhile 表示 但java也提供了另一种循环语句 for循环 使一些循环结构变得更加简单  for循环执行的次数是在执行前就确定的  格式:for(初始值;布尔表达式;步进){//代码语句}关于for循环有以下几点说明:最先执行初始化步骤  可以声明一种类型 但可初始化一个或多个循环控制变量 也可以是空语句检查布尔表达式的值 如果为true  循环体被执行如果为false 则终止循环 开始执行循环体后面的语句执行一次循环后  更新循环控制变量再次检查布尔表达式的值 循环执行上面的过程例如:java 增加for循环  for循环是从java5开始引入的一种主要用于数组的增强型for循环for(声明语句:表达式)声明语句:声明新的局部变量 该变量的类型必须和数组元素的类型匹配 其作用域定在循环语句块 其值与此时数组元素的值是等价的表达式:表达式是要访问的数组名  或者返回值为数组的方法  例如:break关键字  break主要用在循环语句或者switch语句中用来跳出整个语句块break跳出最里层的循环 并且继续执行该循环下面的语句;语法:break是循环结构中的一条语句  break;实例代码:continue关键字  continue适用于任何循环控制结构中作用是让程序立刻跳转到下一次循环的迭代中去在for循环中continue语句使程序立即跳转到更新的语句中在while或者dowhile语句中  程序立即跳转到布尔表达式的判断语句中。语法:continue就是循环体中一条简单的语句:cotinue;这里 java的循环结构就介绍完了 喜欢的小伙伴记得点赞+收藏哈!
  • [技术干货] java第五期干货之修饰符(2)
    访问控制和继承 请注意以下方法继承的规则:1:父类中声明为public的放啊在子类中必须也要用public方法2:父类中声明为protected的方法在子类中要么声明protected要么声明为public不能声明为private3:父类中声明为private的方法不能够被继承非访问修饰符为了实现一些其他的功能 java提供了俩个修饰符 为访问和非访问修饰符static修饰符 用离开修饰类方法和类类变量final修饰符用来修饰 类 方法和变量 final修饰的类不能够被继承 修饰的方法不能被继承类重新定义 修的变量为常量是不可更改的abstract 修饰符用来创建抽象类和筹建方法synchronized主要用来线程的编辑static修饰符静态变量:static关键字用来声明独立于对象的静态变量 无论一个类实例化多少对象他的静态变量只有一份拷贝  静态变量也成为类变量  局部变量不能被声明为static变量静态方法:static关键字用声明独立于对象的静态方法  静态方法 不能使用类的非静态变量  静态方法从参数列表得到数据 然后计算这些数据对类变量和方法的访问可以直接使用lclassname.variablename和classname.methodname的方式访问。 class InstanceCounter { private int numInstances = 0; protected int getCount() { return numInstances; } private void addInstance() { numInstances++; } InstanceCounter() { InstanceCounter.addInstance(); } public static void main(String[] arguments) { System.out.println("Starting with " + InstanceCounter.getCount() + " instances"); for (int i = 0; i < 500; ++i) { new InstanceCounter(); } System.out.println("Created " + InstanceCounter.getCount() + " instances"); } }}结果为:Starting with 0 instancesCreated 500 instancesfinal 修饰符 final变量  final表示最后的含义 变量一旦被符之后不能被重新赋值 被final修饰的实力变量必须显示指定的初始值 (重点)final方法 父类中的final方法可以被子类继承  但是不能被子类从写声明final方法的主要目的是防止该方法的内容被修改如下:  public final void changename(){//方法体}final类 性质:final类不能被继承 没有任何类可以继承final类的任何特性例:public final classtext{//类体}abstract修饰符抽象类性质:抽象类不能实例化对象 声明抽象类的唯一目的是为了将来对该类进行扩充一个类不能同时被抽象类和final类修饰 如果一个类包含抽象方法 那么该类一定要声明为抽象类  否则编译出错例:abstract class cat{private double price;private String model;private String year;public abstract void gofast();public abstract void change color();抽象方法抽象方法是一种没有任何实现的方法 该方法的具体实现由子类提供抽象方法不能被声明为final和静态任何继承抽象类的子类必须实现父类的all抽象方法,除非该子类也是抽象类如果一个类包含若干个抽象方法那么该类必须声明为抽象类 抽象类可以不包含抽象方法。即 抽象类可以不包含抽象方法 但是抽象方法必须在抽象类中声明抽象方法的声明以分号结尾:如 public abstract sample();public abstract class SuperClass{ abstract void m(); //抽象方法}class SubClass extends SuperClass{ //实现抽象方法 void m(){ ......... }}抽象类到此就彻底结束了~感谢大家的耐心阅读 记得点赞+收藏哈
  • [技术干货] java干货第四期之修饰符
    java语言中提供了很多修饰符  主要分为俩类:1:访问修饰符2:非访问修饰符修饰符用来定义类 方法或者变量 通常放在语句的最前端  举个例子:访问类修饰符  java中可以使用访问控制符来保护对类  变量 方法 和构造方法的访问 java支持4中不同访问的权限default  默认 什么也不写  不适用任何修饰符private 在用一个类内可见  使用对象 变量 方法  注意 不能修饰类 外部类public  对所有类可见 使用对象:类 接口 变量 方法protected  对同一包内的类和所有子类可见 使用对象:变量 方法  注意和private意义不能修饰外部类相信大家学习java时老师会给大家列一个表格 来一次人间清醒 这里就不画了哈默认访问修饰符  不适用任何关键字使用默认访问修饰符生命的变量和方法对同一个包内得到类是可见的  接口的变量都生命为:public  static final 而接口里的方法默认情况下访问权限为 public像这样变量和方法的声明可以不适用任何修饰符String version = "1.5.1"; boolean processOrder() { return true; }私有访问修饰符 private 私有访问修饰符是最严格 的访问级别 所以被称为private的方法 变量和构造方法只能被所属类访问  并且类和接口不能声明为private  生命为私有访问类型的变量只能通过类中公共的getter方法被外部所访问private 访问修饰符的使用主要用来因此类的实现细节和保护类的数据如:public class cat{ private String format; public String getFormat; return this.format;}public void setFormat(String format){ this.format=format;}实例中logger类中的format变量为私有变量  所以其他类不能直接得到和设置该变量的值 为了使其他类能够操作该变量 定义了俩个public方法  getformat()和setformat(string)get是返回format的值 set是设置format的值共有访问修饰符-public被声明为public的类 方法构造方法和接口能够被任何其他访问类所访问如果有几个相互访问的public类分布在不同的包中 则需要导入相应的public类所在的包 由于类的继承性 类所有的公有方法和变量都能被其子类继承例:public static void main(String[]arguments){//.......}java程序的main方法必须设置成共有的 否则 java解释器将不执行该类受保护的访问修饰符 protected从俩点入手:子类与基类在一个包中   子类和基类不在同一个 包中1:被声明为protected的变量 方法和构造器能被同一个包中的任何其他类所访问2:那么在子类中 子类实例可以访问其从基类继承而来的protected方法而不能访问基类实例的protected方法protected可以修饰数据成员 构造放啊 方法成员 唯独不能修饰外部类接口及接口成员和成员方法不能生命为protected  子类能访问protected修饰符生命的方法和变量 这样就能保护不想挂按的类使用这些方法和变量下面的弗雷使用了protected访问修饰符子类重写弗雷的openspeaker()方法public class Main { public boolean main(String[] args) { class AudioPlayer { protected boolean openSpeaker(Speaker sp) { // 实现细节 } } class StreamingAudioPlayer extends AudioPlayer { protected boolean openSpeaker(Speaker sp) { // 实现细节 } }}如果把openspeaker()方法声明为private 那么除了audioplayer之外的类将不能访问该方法。如果把openspeaker()声明为public 那么所有的类都能够访问该方法如果我们只想让该方法对其所在类的子类可见  则将该方法声明为protected第四次java之修饰符结束一半了哦  写文章不易 建议点赞+收藏!
  • [技术干货] java干活分享之正则表达式
    用途:正则表达式用来定义字符串模式、还可以用来搜索 编辑 处理文本。什么是正则表达式呢?其实一个字符串就是一个简单的正则表达式  如:hello java 匹配到的正则表达式就”hello java“  那就有人问了 特殊符号例如 点号 .  也是正则表达式么?回答是对的点号匹配到的字符 如 "a" 或"1"举例: this is java 匹配字符串 "this is java"            this\s+is\s+java 注意字符串中的\s+ 匹配单词this后面的\s可以匹配多个空格 之后匹配is字符串 在之后\s匹配多个空格然后在跟上java字符串            匹配结果:this is java           ^\d+(\.\d+)?  ^定义了以什么开始  \d匹配一个或多个数字 ?设置括号内的选项是可选的  \匹配""  可以匹配的例子:  "5","1.5","3.8"学过perl的都知道其实java 的正则表达式和perl是最为相似的java util regex包主要包括以下三个类:pattern类:              作用:pattern对象是一个正则表达式的编译。pattern类没有公共的构造方法 要创建一个pattern对象 必须先调用其公共静态编译方法 它返回一个pattern对象 该方法接受一个正则表达式的参数matcher类:             作用:matcher对象是对输入字符串进行解释和匹配操作的引擎 与pattern类一样 matcher也没有公共的构造方法  需要调用pattern对象的matcher方法获得一个matcher对象patternsyntaxexception            作用:其是一个非强制的异常类  它表示一个正则表达式模式中的语法错误举个例子吧:学过正则表达式的知道名词:捕捉组捕捉组是把多个字符当一个单独的单元进行处理的方法它提供对括号内的字符分组来创建例如:正则表达式(cat)创建了一个单一分组  组内包含:"d"  "o"  "g"捕捉组通过从左至右计算其开括号来编号例如 ((A)(B)(C))有这样四个分组:(A)  ((A)(B)(C)) )(B)(C)  (C)  可以通过调用matcher对象的groupcount 方法来查看表达式到底分了多少组  groupcount 方法返回一个int值  表示matcher对象当前有多个捕捉组还有一个特殊的组group(0) 它总是代表整个表达式 该组不包括在groupcount的返回值中举个实例:正则表达式语法:在其他语言中,\\表示我想要在这边负责vu挨打事故这个i部分插入一个普通的反斜杠 请不要给他任何特殊的意义;(其实就是c语言中的转义字符)在java中\\表示我要插入一个正则表达式的反斜杠,所以后面的字符有特殊的意义所以在其他的语言中 如 c  pert  一个反斜杠就足以具有转义的作用 而在java中正则表达式中则需要有俩个反斜杠菜鸟被解析为其他语言中的转义作用。这就是为什么表示一位数字的正则表达式是\\d而 表示一个普通的反斜杠是\\\\索引方法:pubilc int start()  返回以前匹配的初始索引public int start(int group) 返回在以前的匹配操作期间 由给定组所捕获的子序列的初始索引public int end()返回最后匹配字符之后的偏移量public int end(int group) 返回在以前的匹配操作期间由给定组所捕获子序列的最后字符之后的偏移量举例:那第三期的java之正则表达式就到此结束啦~喜欢的小伙伴点赞加收藏~
  • [技术干货] java开发(2)---日期和时间
    java util包中提供了date类来封装当前的日期和时间。date类提供俩个构造函数来实例化date对象.1:第一个构造函数使用当前日期和时间来初始化对象。 date()2:第二个构造函数接受一个参数,该参数必须从1970年1月1日1分1秒起。date(long millisec)date创建以后可以调用下面的方法 6种方法1:boolean afther (date date) 含义:若当调用此方法的Date对象在指定日期之后返回true,否则返回false。2:  boolean  before(date date)含义:若当调用此方法的Date对象在指定日期之前返回true,否则返回false。3:  object clone()                      含义:返回该对象的副本4:  int compare to(date date)   含义:当调用次此方法的date对象和指定日期作比较时 二者相等时返回0 调用对象在指定日期之前返回负值,调用对象在指定日期之后返回正值。5:long get time()                   含义:返回自1970年开始对象得到毫秒数6:  int has code()                      含义:返回调用对象的哈希值举个例子:如何获取当前日期和时间呢?使用datre对象的tostring()方法打印当前日期和时间上次我们说到 字符串有比较 那日期的比较呢?又有几种形式呢?1:使用gettime() 方法获取俩个日期 然后比较二者值大小2:使用上面提到过的before() afther()和equals()例如 3月比4月早  newdate(21,3)before(new date(21,4))结果返回true3:使用compareto() 的方法 该方法由comparable接口定义,date实现了这个接口并提供类调用时的方法。格式化:如何利用类放啊使得日期被格式化呢?利用simpledateformat是一个以语言环境敏感的方式来格式化和分析日期的类。好处:该类允许你选择任何用户自定义的日期时间格式来执行simpledateformat ft=new simpledateformat(“yyyy-mm-dd hh:mm:ss”);这一行确定了转化的格式:其中yyyy是完整的公元年,mm是month的首字符 月份 以此类推常见的日期格式有:y  四位年份  yyyy  2021m 月份        可以是英文或阿拉伯数字 如:july或07d 一个月的日期  10  20 30h 采用十二进制显示日小时 1~12m 分钟数 1~60d 一年中的日子  360天f 一个月中第几周的星期几  2 (second wed injuly)s 秒数 1~60秒如何用printf格式化日期呢?c 包括全部日期和时间信息f  年月日格式d 月日年格式r  hh:mm:ss pm格式综合上述方法实现下:
  • [技术干货] java开发(1)string类
    字符串广泛应用在java编程中 在java中字符串属于对象  而且提供了string类来创建和操作字符串如何创建一个字符串呢? string str="xiannbenxian";在代码中遇到字符串常量时 这里的赋值为"xiannbenxian",编译器会使用该值创建一个对象 如何用构造方法创建字符串呢?string strr2=new string("xiannbenxian");string创建的字符串存储在公共池中 而new 创建的字符串string对象在堆上面 这是二者的区别;string s1="xiannbenxian";string s2="xiannbenxian";string s3=s1;string s4=new string("xiannbenxian");string s5=new string("xiannbenxian");这里面s1和s2是直接创建  s3中相同引用 s4和s5是字符串string对象创建 string类有11种构造方法 这些方法提供的不同的参数来初始化字符串 比如提供一个字符数组参数:2:如何像c语言使得俩个字符串连接在一起呢?方法1:string1.concat(string2);意义:返回string2连接string1的新字符串,也可以对字符串常量使用concat()方法 例:"我叫仙女本仙".concat("哇");更常用的是使用'+'操作来连接字符串, "hello,"+"java"+"!"输出:hello,java!例子:3:如何创建格式化字符串呢?举个例子 我们知道输出格式化数字可以使用print()和format()方法,string类使用静态方法format()返回一个string对象而不是printstram对象。              string类的静态方法 format()能用来创建可复用的格式化字符串,而不是仅仅用于一次打印输出例如:也可以等价换成:
  • 利用java+API开发云存储
        首先搭建idea中所需要的maven环境    查看maven环境是否搭建成功    写测试代码(openstack4Test和jcloudTest),测试是否可以和虚拟机连接成功    运行openstack4测试方法是否成功    运行jcloud测试方法测试是否连接成功    连接虚拟机成功后先写一个index页面作为登录页面    编辑配置文件application.yml文件    首先搭建idea中所需要的maven环境    查看maven环境是否搭建成功    写测试代码(openstack4Test和jcloudTest),测试是否可以和虚拟机连接成功    运行openstack4测试方法是否成功    运行jcloud测试方法测试是否连接成功    连接虚拟机成功后先写一个index页面作为登录页面    编辑配置文件application.yml文件    首先搭建idea中所需要的maven环境    查看maven环境是否搭建成功    写测试代码(openstack4Test和jcloudTest),测试是否可以和虚拟机连接成功    运行openstack4测试方法是否成功    运行jcloud测试方法测试是否连接成功    连接虚拟机成功后先写一个index页面作为登录页面    编辑配置文件application.yml文件    首先搭建idea中所需要的maven环境    查看maven环境是否搭建成功    写测试代码(openstack4Test和jcloudTest),测试是否可以和虚拟机连接成功    运行openstack4测试方法是否成功    运行jcloud测试方法测试是否连接成功    连接虚拟机成功后先写一个index页面作为登录页面    编辑配置文件application.yml文件    创建一个controller包,在controller包里创建一个类,让这个类首先实现到login页面的跳转    测试是否可以跳转到登录页面    在类里实现login连接到远程虚拟机上,同时在po包里创建实体类。代码功能在截图里进行介绍。
  • java云接口_华为云JavaAPI调用数据设备接口(虚拟设备)
    注意:重置密钥时,除了密钥与id改变,其余都不变API接口Demo:https://support.huaweicloud.com/devg-IoT/iot_02_3002.html参考网址:https://huaweicloud.blog.csdn.net/article/details/103934131
  • [技术干货] ROMA现场的私有云无法importClass(javax.crypto.spec.SecretKeySpec)
    项目名称:浙江金华智慧花园项目问题描述:在公有云的ROMA(https://studioroma.e.huawei.com/roma/#/)下存在javax.crypto.spec.SecretKeySpec能够正常import,然而到了现场的私有云环境上述类无法import。截图为现场的私有云环境的现象。
  • STL deque容器
    STL中的容器:deque容器的常用接口及用法:deque:它被称作双端数组,可以在头部和尾部插入或删除数据;deque 容器和 vector 容器的区别:1.vector 容器对头部插入、删除数据的效率较低,因为 vector 容器是单端数组,若要从头部插入或删除,得把后面的数据都往后挪或往前挪,因此数据量越大,则其时间效率越低;2.deque 容器相对 vector 容器而言,它对于头部插入数据或头部删除数据的效率就高多了,这与它的内部实现相关;3.vector 容器访问单个数据的效率要高于 deque 容器,原因也是与 deque 容器的内部实现有关;图片转自于黑马程序员,是在学习的过程中截图下来的deque 容器内部工作原理:1.deque 内部有个中控器,它维护着每段缓冲区中的内容,而缓冲区里面放着真实的数据;2.中控器维护的其实是缓冲区的地址,使得使用 deque 容器时像一段连续的内存空间;3.缓冲区的头和尾是没有插满数据的,因此可以继续添加。添加满后,则会开辟一块新的缓冲区,中控器则记录下新的缓冲区的地址;4.由于中控器维护的是地址,因此当我们访问单个元素时,内部的实现是从地址再转到缓冲区,这里的时间效率就低于 vector 容器了;
  • [技术干货] 40个问题让你快速掌握Java多线程的精髓(4)
    四、线程池Q: ThreadPoolExecutor线程池构造参数中,corePoolSize和maximumPoolSize有什么区别?A:当提交新线程到池中时如果当前线程数 < corePoolSize,则会创建新线程如果当前线程数=corePoolSize,则新线程被塞进一个队列中等待。如果队列也被塞满了,那么又会开始新建线程来运行任务,避免任务阻塞或者丢弃如果队列满了的情况下, 线程总数超过了maxinumPoolSize,那么就抛异常或者阻塞(取决于队列性质)。调用prestartCoreThread()可提前开启一个空闲的核心线程调用prestartAllCoreThreads(),可提前创建corePoolSize个核心线程。Q: 线程池的keepalive参数是干嘛的?A:当线程数量在corePoolSize到maxinumPoolSize之间时, 如果有线程已跑完,且空闲时间超过keepalive时,则会被清除(注意只限于corePoolSize到maxinumPoolsize之间的线程)Q: 线程池有哪三种队列策略?A:握手队列相当于不排队的队列。可能造成线程数量无限增长直到超过maxinumPoolSize(相当于corePoolSize没什么用了,只以maxinumPoolSize做上限)无界队列队列队长无限,即线程数量达到corePoolSize时,后面的线程只会在队列中等待。(相当于maxinumPoolSize没什么用了)缺陷: 可能造成队列无限增长以至于OOM有界队列Q: 线程池队列已满且maxinumPoolSize已满时,有哪些拒绝策略?A:AbortPolicy 默认策略:直接抛出RejectedExecutionException异常DiscardPolicy 丢弃策略: 直接丢了,什么错误也不报DiscardOldestPolicy 丢弃队头策略: 即把最先入队的人从队头扔出去,再尝试让该任务进入队尾(队头任务内心:不公平。。。。)CallerRunsPolicy 调用者处理策略: 交给调用者所在线程自己去跑任务(即谁调用的submit或者execute,他就自己去跑)也可以用实现自定义新的RejectedExecutionHandlerQ:有以下五种Executor提供的线程池,注意记忆一下他们的用途,就能理解内部的原理了。newCachedThreadPool: 缓存线程池corePoolSize=0, maxinumPoolSize=+∞,队列长度=0 ,因此线程数量会在corePoolSize到maxinumPoolSize之间一直灵活缓存和变动, 且不存在队列等待的情况,一来任务我就创建,用完了会释放。newFixedThreadPool :定长线程池corePoolSize= maxinumPoolSize=构造参数值, 队列长度=+∞。因此不存在线程不够时扩充的情况newScheduledThreadPool :定时器线程池提交定时任务用的,构造参数里会带定时器的间隔和单位。 其他和FixedThreadPool相同,属于定长线程池。newSingleThreadExecutor : 单线程池corePoolSize=maxinumPoolSize=1, 队列长度=+∞,只会跑一个任务, 所以其他的任务都会在队列中等待,因此会严格按照FIFO执行newWorkStealingPool(继承自ForkJoinPool ): 并行线程池如果你的任务执行时间很长,并且里面的任务运行并行跑的,那么他会把你的线程任务再细分到其他的线程来分治。ForkJoinPool介绍:https://blog.csdn.net/m0_37542889/article/details/92640903Q: submit和execute的区别是什么?A:execute只能接收Runnable类型的任务,而submit除了Runnable,还能接收Callable(Callable类型任务支持返回值)execute方法返回void, submit方法返回FutureTask。异常方面, submit方法因为返回了futureTask对象,而当进行future.get()时,会把线程中的异常抛出,因此调用者可以方便地处理异常。(如果是execute,只能用内部捕捉或者设置catchHandler)Q:线程池中, shutdown、 shutdownNow、awaitTermination的区别?A:shutdown: 停止接收新任务,等待所有池中已存在任务完成( 包括等待队列中的线程 )。异步方法,即调用后马上返回。shutdownNow: 停止接收新任务,并 停止所有正执行的task,返回还在队列中的task列表 。awaitTermination: 仅仅是一个判断方法,判断当前线程池任务是否全部结束。一般用在shutdown后面,因为shutdown是异步方法,你需要知道什么时候才真正结束。五、Thread状态转换Q: 线程的6种状态是:A:New: 新建了线程,但是还没调用startRUNNABLE: 运行, 就绪状态包括在运行态中BLOCKED: 阻塞,一般是因为想拿锁拿不到WAITING: 等待,一般是wait或者join之后TIMED_WAITING: 定时等待,即固定时间后可返回,一般是调用sleep或者wait(时间)的。TERMINATED: 终止状态。欣赏一幅好图,能了解调用哪些方法会进入哪些状态。Q: java线程什么时候会进入阻塞(可能按多选题考):A:sleepwati()挂起, 等待获得别的线程发送的Notify()消息等待IO等待锁六、Volatile用volatile修饰成员变量时, 一旦有线程修改了变量,其他线程可立即看到改变。Q: 不用volatile修饰成员变量时, 为什么其他线程会无法立即看到改变?A:线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值。Q: 用了volatile是不是就可以不用加锁啦?A: 不行。锁并不是只保证1个变量的互斥, 有时候是要保证几个成员在连续变化时,让其他线程无法干扰、读取。而volatile保证1个变量可变, 保证不了几个变量同时变化时的原子性。Q:展示一段《Java并发编程实战》书里的一个经典例子,在科目二考试里也出现了,只是例子换了个皮。为什么下面这个例子可能会死循环,或者输出0?:首先理解一下java重排序,可以看一下这篇博文:https://www.cnblogs.com/coshaho/p/8093944.html然后分析后面那2个奇怪的情况是怎么发生的。永远不输出:经过程序的指令排序,出现了这种情况:ReaderThread在while里读取ready值, 此时是false, 于是存入了ReaderThread的寄存器。主线程修改ready和number。ReaderThread没有感知到ready的修改(对于ReaderThread线程,感知不到相关的指令,来让他更新ready寄存器的值),因此进入死循环。输出0经过程序的指令排序,出现了这种情况:1)主线程设置ready为true2)ReaderThread在while里读取ready值,是true,于是退出while循环ReaderThread读取到number值, 此时number还是初始化的值为0,于是输出0主线程这时候才修改number=42,此时ReaderThread已经结束了!上面这个问题,可以用volatile或者加锁。当你加了锁时, 如果变量被写了,会有指令去更新另一个寄存器的值,因此就可见了。七、线程群组为了方便管理一批线程,我们使用ThreadGroup来表示线程组,通过它对一批线程进行分类管理使用方法:Thread group = new ThreadGroup("group");Thread thread = new Thread(gourp, ()->{..});即thread除了Thread(Runable)这个构造方法外,还有个Thread(ThreadGroup, Runnable)构造方法Q:在线程A中创建线程B, 他们属于同一个线程组吗A:是的线程组的一大作用是对同一个组线程进行统一的异常捕捉处理,避免每次新建线程时都要重新去setUncaghtExceptionHandler。即线程组自身可以实现一个uncaughtException方法。ThreadGroup group = new ThreadGroup("group") {    @Override    public void uncaughtException(Thread thread, Throwable throwable) {        System.out.println(thread.getName() + throwable.getMessage());        }    };}线程如果抛出异常,且没有在线程内部被捕捉,那么此时线程异常的处理顺序是什么?相信很多人都看过下面这段话,好多讲线程组的博客里都这样写:(1)首先看看当前线程组(ThreadGroup)有没有父类的线程组,如果有,则使用父类的UncaughtException()方法。(2)如果没有,就看线程是不是调用setUncaughtExceptionHandler()方法建立Thread.setUncaughtExceptionHandler实例。如果建立,直接使用它的UncaughtException()方法处理异常。(3)如果上述都不成立就看这个异常是不是ThreadDead实例,如果是,什么都不做,如果不是,输出堆栈追踪信息(printStackTrace)。来源:https://blog.csdn.net/qq_43073128/article/details/90597006https://blog.csdn.net/qq_43073128/article/details/88280469好,别急着记,先看一下下面的题目,问输出什么:Q:// 父类线程组static class GroupFather extends ThreadGroup {    public GroupFather(String name) {        super(name);    }    @Override    public void uncaughtException(Thread thread, Throwable throwable) {        System.out.println("groupFather=" + throwable.getMessage());    }} public static void main(String[] args) {    // 子类线程组    GroupFather groupSon = new GroupFather("groupSon") {        @Override        public void uncaughtException(Thread thread, Throwable throwable) {            System.out.println("groupSon=" + throwable.getMessage());        }    };    Thread thread1 = new Thread(groupSon, ()->{        throw new RuntimeException("我异常了");    });    thread1.start();}A:一看(1),那是不是应该输出groupFather?错错错,输出的是groupSon这句话在很多地方能看到,但没有去实践过看过源码的人就会这句话被误导。实际上父线程组不是指类继承关系上的线程组,而是指下面这样的:即指的是构造关系的有父子关系。如果子类的threadGroup没有去实现uncaughtException方法,那么就会去构造参数里指定的父线程组去调用方法。Q: 那我改成构造关系上的父子关系,下面输出什么?public static void main(String[] args) {    // 父线程组    ThreadGroup groupFather = new ThreadGroup("groupFather") {        @Override        public void uncaughtException(Thread thread, Throwable throwable) {            System.out.println("groupFather=" + throwable.getMessage());        }    };     // 子线程组,把groupFather作为parent参数    ThreadGroup groupSon = new ThreadGroup(groupFather, "groupSon") {        @Override        public void uncaughtException(Thread thread, Throwable throwable) {            System.out.println("groupSon=" + throwable.getMessage());        }    };     Thread thread1 = new Thread(groupSon, ()->{        throw new RuntimeException("我异常了");    });     thread1.start();}A:答案输出即只要子线程组有实现过,则会用子线程组里的方法,而不是直接去找的父线程组!Q:如果我让自己做set捕捉器的操作呢?那下面这个输出什么?public static void main(String[] args) {    // 父线程组    ThreadGroup group = new ThreadGroup("group") {        @Override        public void uncaughtException(Thread thread, Throwable throwable) {            System.out.println("group=" + throwable.getMessage());        }    };     // 建一个线程,在线程组内    Thread thread1 = new Thread(group, () -> {        throw new RuntimeException("我异常了");    });     // 自己设置setUncaughtExceptionHandler方法    thread1.setUncaughtExceptionHandler((t, e) -> {        System.out.println("no gourp:" + e.getMessage());    });     thread1.start();}A:看之前的结论里,似乎是应该输出线程组的异常?但是结果却输出的是:也就是说,如果线程对自己特地执行过setUncaughtExceptionHandler,那么有优先对自己设置过的UncaughtExceptionHandler做处理。那难道第(2)点这个是错的吗?确实错了,实际上第二点应该指的是全局Thread的默认捕捉器,注意是全局的。实际上那段话出自ThreadGroup里uncaughtException的源码:这里就解释了之前的那三点,但是该代码中没考虑线程自身设置了捕捉器所以修改一下之前的总结一下线程的实际异常抛出判断逻辑:如果线程自身有进行过setUncaughtExceptionHandler,则使用自己设置的按个。如果没设置过,则看一下没有线程组。并按照以下逻辑判断:如果线程组有覆写过uncaughtException,则用覆写过的uncaughtException如果线程组没有覆写过,则去找父线程组(注意是构造体上的概念)的uncaughtException方法。如果线程组以及父类都没覆写过uncaughtException, 则判断是否用Thread.setDefaultUncaughtExceptionHandler(xxx)去设置全局的默认捕捉器,有的话则用全局默认如果不是ThreadDeath线程, 则只打印堆栈。如果是ThreadDeath线程,那么就什么也不处理。
  • [技术干货] 40个问题让你快速掌握Java多线程的精髓(3)
    二、synchronized关键字即可作为方法的修饰符,也可以作为代码块的修饰符注意修饰方法时,并不是这个方法上有锁, 而是调用该方法时,需要取该方法所在对象上的锁。class A{     synchroized f(){     }   }即调用这个f(), 并不是说f同一时刻只能进入一次,而是说进入f时,需要取到A上的锁。Q: 调用下面的f()时,会出现死锁吗?class A{     synchroized f(){        t()     }      synchroized t(){     }}A:不会。1个线程内, 可以重复进入1个对象的synchroized 块。原理:当线程请求自己的锁时。JVM会记下锁的持有者,并且给这个锁计数为1。如果该线程再次请求自己的锁,则可以再次进入,计数为2。退出时计数-1,直到全部退出时才会释放锁。Q:2个线程同时调用f1和f2会产生同步吗?class A{    private static synchronized void f1(){};    private synchronized void f2(){};}A:不会产生同步。二者不是1个锁。f1是类锁,等同于synchronized(A.class)f2是对象锁。三、其他的同步工具CountDownLatchfinal CountDownLatch latch = new CountDownLatch(2);2是计数器初始值。然后执行latch.await()时, 就会阻塞,直到其他线程中把这个latch进行latch.countDown(),并且计数器降低至0。和join的区别:join阻塞时,是只等待单个线程的完成而CountDownLatch可能是为了等待多个线程Q: countDownLatch的内部计数值能被重置吗?A:不能重置了。如果要重新计数必须重新new一个。毕竟他的类名就叫DownLatchFutureTask可以理解为一个支持有返回值的线程FutureTask<Integer> task = new FutureTask<>(runable);当调用task.get()时,就能能达到线程里的返回值Q:调用futrueTask.get()时,这个是阻塞方法吗?如果是阻塞,什么时候会结束?A:是阻塞方法。线程跑完并返回结果阻塞时间达到futrueTask.get(xxx)里设定的xxx时间线程出现异常InterruptedException或者ExecutionException线程被取消,抛出CancellationExceptionSemaphore信号量:就是操作系统里常见的那个概念,java实现,用于各线程间进行资源协调。用Semaphore(permits)构造一个包含permits个资源的信号量,然后某线程做了消费动作, 则执行semaphore.acquire(),则会消费一个资源,如果某线程做了生产动作,则执行semaphore.release(),则会释放一个资源(即新增一个资源)更详细的信号量方法说明:https://blog.csdn.net/hanchao5272/article/details/79780045Q: 信号量中,公平模式和非公平模式的区别?下面设成true就是公平模式//new Semaphore(permits,fair):初始化许可证数量和是否公平模式的构造函数semaphore = new Semaphore(5, true);A:其实就是使用哪种公平锁还是非公平锁。Java并发中的fairSync和NonfairSync主要区别为:如果当前线程不是锁的占有者,则NonfairSync并不判断是否有等待队列,直接使用compareAndSwap去进行锁的占用,即谁正好抢到,就给谁用!如果当前线程不是锁的占有者,则FairSync则会判断当前是否有等待队列,如果有则将自己加到等待队列尾,即严格的先到先得!CyclicBarrier栅栏,一般是在线程中去调用的。它的构造需要指定1个线程数量,和栅栏被破坏前要执行的操作,每当有1个线程调用barrier.await(),就会进入阻塞,同时barrier里的线程计数-1。当线程计数为0时, 调用栅栏里指定的那个操作后,然后破坏栅栏, 所有被阻塞在await上的线程继续往下走。Exchanger我理解为两方栅栏,用于交换数据。简单说就是一个线程在完成一定的事务后,想与另一个线程交换数据,则第一个先拿出数据的线程会一直等待第二个线程,直到第二个线程拿着数据到来时才能彼此交换对应数据。原子类AtomicXXX就是内部已实现了原子同步机制Q:下面输出什么?(考察getAndAdd的用法)AtomicInteger num = new AtomicInteger(1);System.out.println(num.getAndAdd(1));System.out.println(num.get());A:输出1、2顾名思义, getAndAdd(),那么就是先get,再加, 类似于num++。如果是addAndGet(),那么就是++numQ:AtomicReference和AtomicInteger的区别?A:AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。即可能会有多个线程修改atomicReference里包含的引用。经典用法:boolean exchanged = atomicStringReference.compareAndSet(initialReference, newReference)就是经典的CAS同步法compreAndSet它会将将引用与预期值(引用)进行比较,如果它们相等,则在AtomicReference对象内设置一个新的引用。类似于一个非负责的自旋锁。AtomicReferenceArray是原子数组, 可以进行一些原子的数组操作例如 set(index, value),java中已实现的全部原子类:注意,没有float,没有short和byte。
总条数:2294 到第 页
上滑加载中