首页 文章 精选 留言 我的

精选列表

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

Java通过反射机制修改类中的私有属性的值

首先创建一个类包含一个私有属性: class PrivateField{ private String username = "Jason"; } 通过反射机制修改username的值: //创建一个类的对象 PrivateField privateField = new PrivateField(); //获取对象的Class Class<?> classType = privateField.getClass(); //获取指定名字的私有域 Field field = classType.getDeclaredField("username"); //设置压制访问类型检查,只有这样,才能获取和设置某个具体类的Field对应的值。 field.setAccessible(true); System.out.println(field.get(privateField)); //设置私有域的值 field.set(privateField, "aaaaa"); System.out.println(field.get(privateField)); 我是天王盖地虎的分割线 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3882731.html,如需转载请自行联系原作者

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

Java从入门到放弃》JavaSE入门篇:程序结构

程序的结构一般分为三种: 顺序结构。 选择结构。 循环结构。 一、顺序结构:这个不用多说吧,跟我们平时写文章的顺序一样,从上往下。 二、选择结构:从名字就能看出,要选择嘛,到底是要漂亮滴妹子,还是要有钱滴妹子呢!当然,如果是个吊丝码农滴话,那你就不要多想了,还是老老实实码代码吧··· 三、循环结构:循环啊,就是一直转啊转啊转啊,转到出意外为止。 接下来还是老规矩,通过小示例来学习语法吧。 顺序结构: 一、输入姓名和年龄,输出自我介绍。 publicstaticvoidmain(String[]args){ //创建输入数据的对象,具体什么叫对象···,先不用管吧 Scannerinput=newScanner(System.in); Stringname;//姓名 intage;//年龄 System.out.print("请输入姓名:"); name=input.next(); System.out.print("请输入年龄:"); age=input.nextInt(); System.out.println("大家好,我叫"+name+",今年"+age+"岁,请多关照。"); } 注意: 这就是一个标准的顺序结构,代码会从上往下执行,如果你把int age;这句话放到最后,那就会在age = input.nextInt();这一行报语法错误了。 结果: 选择结构: 选择结构的语法有四种,我们通过下面的案例来了解。 一、输入你的存款,如果大于5000则加上“壕”的头衔。 publicstaticvoidmain(String[]args){ //创建输入数据的对象,具体什么叫对象···,先不用管吧 Scannerinput=newScanner(System.in); Stringname;//姓名 intdeposit;//存款 System.out.print("请输入姓名:"); name=input.next(); System.out.print("请输入存款:"); deposit=input.nextInt(); System.out.print("大家好,我叫"+name); if(deposit>5000){ System.out.print("(壕)"); } System.out.println("。"); } 语法: if( 条件 ){ 要执行的代码 } 注意: 条件成立时会执行{}中的所有代码。 结果: 二、输入你的存款,如果大于5000则加上“壕”的头衔,否则加上“穷13”的头衔。 if(deposit>5000){ System.out.print("(壕)"); } else{ System.out.print("(穷13)"); } 注意:别的代码不用动,只需要在if(){}结构上加上else{}就OK了,else{}表示条件不成立时的执行代码。 结果: 三、输入你的存款,如果大于50000,则加上“神壕”的头衔,否则如果大于30000,则加上“金壕”的头衔,否则如果大于10000,则加上“壕”的头衔,否则加上“穷13”的头衔。 if(deposit>50000){ System.out.print("(神壕)"); } elseif(deposit>30000){ System.out.print("(金壕)"); } elseif(deposit>10000){ System.out.print("(壕)"); } else{ System.out.print("(穷13)"); } 注意:这种语法叫多分支选择结构(一般用于选择情况大于2的场合,比如演唱会门票的级别、你的女神的胸肌是A还是BCDEF等)。 结果就不展示了。 四、查询余额请按1,套餐更改请按2,宽带业务请按3,企业业务请按4,人工服务请按5,其它业务请瞎按. publicstaticvoidmain(String[]args){ //创建输入数据的对象,具体什么叫对象···,先不用管吧 Scannerinput=newScanner(System.in); intnum; System.out.print("1.查询余额请按1," +"\n2.套餐更改请按2" +"\n3.宽带业务请按3" +"\n4.企业业务请按4" +"\n5.人工服务请按5" +"\n6.其它业务请瞎按" +"\n请选择:"); num=input.nextInt(); switch(num){ case1: System.out.println("您的余额为0。");break; case2: System.out.println("改完了,请回吧。");break; case3: System.out.println("宽带装好了,请交钱1998¥。");break; case4: System.out.println("请上传企业注册资料。");break; case5: System.out.println("我们正在招聘服务人员,请稍等...");break; default: System.out.println("乱按好玩吧...");break; } } 注意: switch语法一般用于数值类型和布尔类型等值判断的场合,最新版的JDK支持String类型了。小伙伴们可以自己试试。 每个case后的语句执行完后都有个小尾巴(break;),表示从这儿退出switch结构,大家可以把这个小尾巴去掉看看结果有什么不一样。 结果: 循环结构: 循环结构常用的有四种:while、do...while、for、foreach(后面讲集合时再介绍)。 对应的语法都很简单,我们通过求100以内的奇数和来了解一下,后面再来分析一个经典案例。 publicstaticvoidmain(String[]args){ //求100以内的奇数和 //1.while循环 inti=1;//循环的初值 ints=0;//保存和 while(i<=100){//循环的条件 s+=i;//循环的内容 i+=2;//循环的步长(也就是循环变量的值如何变化) } System.out.println("while循环结果:"+s); //变量值还原 i=1; s=0; //2.do...while循环 do{ s+=i; i+=2; }while(i<=100); System.out.println("do...while循环结果:"+s); //变量值还原 s=0; //3.for循环 for(i=1;i<=100;i+=2){ s+=i; } System.out.println("for循环结果:"+s); } 执行结果: 从上面的语法应该可以看出,循环主要有四个点:初值、条件、步长、循环体(内容)。那么这三种循环的语法有什么区别呢? while循环:侧重于不确定循环次数的场合,先判断,如果条件成立则进入循环。 do...while循环:侧重于不确定循环次数的场合,先执行一次,之后如果条件成立则时入循环。 for循环:侧重于确定循环次数的场合。 与循环配合使用的还有两个关键字:continue和break; 他们的作用,看代码和结果吧: publicstaticvoidmain(String[]args){ for(inti=0;i<10;i++){ if(i==5){ continue; } System.out.print(i+","); } System.out.println("\n======================="); for(inti=0;i<10;i++){ if(i==5){ break; } System.out.print(i+","); } } 结果: 注意到两个的区别了吧 运行continue后,就不再执行循环里面continue后面的代码,直接运行i++去了。 而运行break后,则直接跳出了循环,后面的都不执行了。 经典案例:登录功能,如果账号密码输入正确则登录成功,否则请再次输入密码。 分析: 登录时要输入几次账号密码?很明显不知道啊!!!所以for循环被排除了。 然后再判断,是要先输入账号密码后判断,还是先判断后再输入账号密码呢? 这也很明显,要先输入了才需要判断啊!!!所以while循环也被排除了。 最后就剩下do...while循环了。代码如下: publicstaticvoidmain(String[]args){ //模拟登录功能 //分析过程: //1.定义保存账号和密码的变量 Scannerinput=newScanner(System.in); StringinLoginID; StringinLoginPWD; //2.因为还没学习数据库,所以定义两个变量保存正确的账号和密码 StringloginID="liergou"; StringloginPWD="haha250"; //3.输入账号和密码 do{ System.out.print("请输入账号:"); inLoginID=input.next(); System.out.print("请输入密码:"); inLoginPWD=input.next(); //4.判断输入的账号和密码与正确的是否相同(判断字符串是否相等使用equals方法), //如果相同等提示登录成功,循环结束,否则提示重新输入 if(inLoginID.equals(loginID)&&inLoginPWD.equals(loginPWD)){ System.out.println("登录成功!"); break; } else{ System.out.println("账号和密码不匹配,请重新输入!"); } }while(true); } 如果你非要使用while和for,那··············当然也是可以滴,只不过代码复杂度会上升,特别是使用for来写的话会很奇怪,大伙可以看看: 这是使用while的写法 publicstaticvoidmain(String[]args){ //模拟登录功能 //分析过程: //1.定义保存账号和密码的变量 Scannerinput=newScanner(System.in); StringinLoginID; StringinLoginPWD; //2.因为还没学习数据库,所以定义两个变量保存正确的账号和密码 StringloginID="liergou"; StringloginPWD="haha250"; //3.输入账号和密码 System.out.print("请输入账号:"); inLoginID=input.next(); System.out.print("请输入密码:"); inLoginPWD=input.next(); while(true){ //4.判断输入的账号和密码与正确的是否相同(判断字符串是否相等使用equals方法), //如果相同等提示登录成功,循环结束,否则提示重新输入 if(inLoginID.equals(loginID)&&inLoginPWD.equals(loginPWD)){ System.out.println("登录成功!"); break; } else{ System.out.println("账号和密码不匹配,请重新输入!"); //下面的代码重复了 System.out.print("请输入账号:"); inLoginID=input.next(); System.out.print("请输入密码:"); inLoginPWD=input.next(); } } } 下面是使用for的写法 for(;true;){ //4.判断输入的账号和密码与正确的是否相同(判断字符串是否相等使用equals方法), //如果相同等提示登录成功,循环结束,否则提示重新输入 if(inLoginID.equals(loginID)&&inLoginPWD.equals(loginPWD)){ System.out.println("登录成功!"); break; } else{ System.out.println("账号和密码不匹配,请重新输入!"); //下面的代码重复了 System.out.print("请输入账号:"); inLoginID=input.next(); System.out.print("请输入密码:"); inLoginPWD=input.next(); } } 最后,再布置几个练习,各位看官自己分析并练习练习吧,看具体使用哪种循环最好。 1.打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",因为153=1的三次方+5的三次方+3的三次方。 2.将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。 3. 球从100M高度自由落下,每次落地后反跳回原高度的一半,再落下,求它在第10次落地时,共经过多少M?第10次反弹多高? 4. 任意输入一个整数(小于6位),求它的位数询问 5. “我爱你,嫁给我吧?”,选择“你喜欢我吗?(y/n):",如果输入为y则打印”我们形影不离“,若输入为n,则继续询问 如果有不确定答案的练习,就在评论里讨论吧··· “软件思维”博客地址:51CTO感兴趣的小伙伴可以去看相关的其它博文。

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

Java实现Web页面前数字字母验证码实现

最近公司做项目开发中用到了验证码实现功能,将实现代码分享出来, 前段页面实现代码: <ul> <li><label>验证码:</label></li> <li> <div> <inputtype="text"name="validateCode"class="login_input"value=""/> <imgid="img"src="${baseURL}/validateCode"onclick="onclickValidateCode(this);"/> </div> </li> </ul> 为了表达清晰,样式部分代码去掉了,大家根据自己的需求,自己添加样式。 页面JS代码:触发变动验证码改变的JS <scripttype="text/javascript"language="javascript"> //请求获取验证码 functiononclickValidateCode(obj){ $(obj).attr("src","${baseURL}/validateCode?"+newDate().getTime()); } </script> 后台 Controller处理: packagecom.njcc.pay.controller.login; importjava.awt.Color; importjava.awt.Font; importjava.awt.Graphics; importjava.awt.p_w_picpath.BufferedImage; importjava.io.IOException; importjava.io.OutputStream; importjava.util.Random; importjavax.p_w_picpathio.ImageIO; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importorg.apache.commons.lang3.math.NumberUtils; importorg.apache.commons.logging.Log; importorg.apache.commons.logging.LogFactory; importorg.springframework.stereotype.Controller; importorg.springframework.web.bind.annotation.RequestMapping; importcom.alibaba.dubbo.common.utils.StringUtils; /** *验证马Controller * *@authorAdministrator * */ @Controller publicclassValidateCodeController{ @SuppressWarnings("unused") privatestaticfinalLogLOG=LogFactory.getLog(ValidateCodeController.class); publicstaticfinalStringVALIDATE_CODE="validateCode"; privateintw=70; privateinth=23; /** *@throwsException *函数功能说明:进入后台登陆页面. * *@参数:@return *@returnString *@throws */ @RequestMapping(value="/validateCode") publicvoidvalidateCode(HttpServletRequestrequest, HttpServletResponseresponse)throwsException{ createImage(request,response); } privatevoidcreateImage(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{ response.setHeader("Pragma","no-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires",0); response.setContentType("p_w_picpath/jpeg"); Stringwidth=request.getParameter("width"); Stringheight=request.getParameter("height"); if(StringUtils.isNumeric(width)&&StringUtils.isNumeric(height)){ w=NumberUtils.toInt(width); h=NumberUtils.toInt(height); } BufferedImagep_w_picpath=newBufferedImage(w,h,BufferedImage.TYPE_INT_RGB); Graphicsg=p_w_picpath.getGraphics(); /* *生成背景 */ createBackground(g); /* *生成字符 */ Strings=createCharacter(g); request.getSession().setAttribute(VALIDATE_CODE,s); g.dispose(); OutputStreamout=response.getOutputStream(); ImageIO.write(p_w_picpath,"JPEG",out); out.close(); } /** *生成颜色 *@paramfc *@parambc *@return */ privateColorgetRandColor(intfc,intbc){ intf=fc; intb=bc; Randomrandom=newRandom(); if(f>255){ f=255; } if(b>255){ b=255; } returnnewColor(f+random.nextInt(b-f),f+random.nextInt(b-f),f+random.nextInt(b-f)); } /** *生成背景 *@paramg */ privatevoidcreateBackground(Graphicsg){ //填充背景 g.setColor(getRandColor(220,250)); g.fillRect(0,0,w,h); //加入干扰线条 for(inti=0;i<8;i++){ g.setColor(getRandColor(40,150)); Randomrandom=newRandom(); intx=random.nextInt(w); inty=random.nextInt(h); intx1=random.nextInt(w); inty1=random.nextInt(h); g.drawLine(x,y,x1,y1); } } /** *生成字符 *@paramg *@return */ privateStringcreateCharacter(Graphicsg){ char[]codeSeq={'A','B','C','D','E','F','G','H','J', 'K','M','N','P','Q','R','S','T','U','V','W', 'X','Y','Z','2','3','4','5','6','7','8','9'}; String[]fontTypes={"Arial","ArialBlack","AvantGardeBkBT","Calibri"}; Randomrandom=newRandom(); StringBuilders=newStringBuilder(); for(inti=0;i<4;i++){ Stringr=String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);//random.nextInt(10)); g.setColor(newColor(50+random.nextInt(100),50+random.nextInt(100),50+random.nextInt(100))); g.setFont(newFont(fontTypes[random.nextInt(fontTypes.length)],Font.BOLD,26)); g.drawString(r,15*i+5,19+random.nextInt(8)); // g.drawString(r,i*w/4,h-5); s.append(r); } returns.toString(); } }

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

java线程总结--synchronized关键字,原理以及相关的锁

在多线程编程中,synchronized关键字非常常见,当我们需要进行“同步”操作时,我们很多时候需要该该关键字对代码块或者方法进行锁定。被synchronized锁定的代码块,只能同时有一条线程访问该代码块。 上面是很多人的认识,当然也是我之前对synchronized关键字的浅显认识,其实上面的观点存在一定的偏差。在参考了很多文章以及自己动手测试过相关代码后,我觉得有必要记录下自己对synchronized关键字的一些理解,在这个过程,会简单说说synchronized关键字的具体实现原理。 一、synchronized:synchronized是锁代码块还是锁对象? synchronized具有同步的功能,更准确说是具有互斥的锁功能,那么,它到底是锁定了相关的代码块还是说锁定了对象数据?答案是锁对象。下面就从synchronized修饰方法和修饰具体代码块两方面理解这个结论:synchronized是锁对象的。 1、synchronized修饰方法 废话不多说,先简单看测试代码: 代码一 publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest1test1=newTest1();newThread(newRunnable(){publicvoidrun(){try{ test1.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start(); newThread(newRunnable(){publicvoidrun(){ test1.secondMethod(); } }).start(); }classTest1{publicsynchronizedvoidfirstMethod()throwsInterruptedException{ System.out.println("firstMethod"); Thread.sleep(2000); }publicvoidsecondMethod(){ System.out.println("secondMethod"); } } 输出结果: firstMethod secondMethod 或者 secondMethod firstMethod 然后,看代码二 publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest1test1=newTest1();newThread(newRunnable(){publicvoidrun(){try{ test1.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start();newThread(newRunnable(){publicvoidrun(){ test1.thirdMethod(); } }).start(); } }classTest1{publicsynchronizedvoidfirstMethod()throwsInterruptedException{ System.out.println("firstMethod"); Thread.sleep(2000); }publicsynchronizedvoidthirdMethod(){ System.out.println("thirdMethod"); } } 结果一直是:firstMethod thirdMethod 所以,我们可以得出以下结论(在理解该结论前读者可以先假设每个对象均有一个锁对象,具体后面讲解synchronized关键字原理时会讲解): synchronize修饰方法时(非静态方法,静态方法稍后讨论),表示某个线程执行到该方法时会锁定当前对象,其他线程不可以调用该对象中含有synchronized关键字的方法,因为这些线程的这些方法要执行前提是要获得该对象的锁。 就上面的例子具体说: 在代码一中,由于secondMethod方法没有synchronized关键字修饰,该方法执行无需获取当前对象的锁,所以secondMethod和firstMethod执行是并行的; 在代码二中,firstMethod和thirdMethod方法均有synchronized关键字修饰,两个方法执行前提是可以获取当前对象的锁,所以两者是无法同时进行的,因为同一个对象中只有一把锁。 ok,理解上面的例子之后,估计读者理解下面的代码就简单很多了,好,上代码: 代码三:修饰静态方法时的情形(只有一个方法有static修饰) publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest2test2=newTest2();newThread(newRunnable(){publicvoidrun(){try{ test2.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start();newThread(newRunnable(){publicvoidrun(){ test2.thirdMethod(); } }).start(); } }classTest2{publicstaticsynchronizedvoidfirstMethod()throwsInterruptedException{ System.out.println("firstMethod"); Thread.sleep(2000); }publicsynchronizedvoidthirdMethod(){ System.out.println("thirdMethod"); } } 执行结果是:firstMethodthirdMethod或者thirdMethodfirstMethod 代码四:(都有static修饰) publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest2test2=newTest2();newThread(newRunnable(){publicvoidrun(){try{ test2.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start();newThread(newRunnable(){publicvoidrun(){ test2.thirdMethod(); } }).start(); } }classTest2{publicstaticsynchronizedvoidfirstMethod()throwsInterruptedException{ System.out.println("firstMethod"); Thread.sleep(2000); }publicstaticsynchronizedvoidthirdMethod(){ System.out.println("thirdMethod"); } } 执行结果是:firstMethod thirdMethod 从上面结果我们可以知道:synchronized修饰静态方法时,它会锁定Class实例对象。 所以代码三中由于firstMethod和thirdMethod锁定对象不同,所以他们可以并行执行;代码四中两个方法都锁定了class对象,所以无法并行执行。 好,上面一大坨的文字,总结一句话起来就是这样: synchronized修饰静态方法时,它表示锁定class对象;修饰动态方法时,表示锁定当前对象(this)。 2、synchronized修饰代码块 其实,上面的讲解已经很明确指出了一个事实:synchronized关键字就是表示当前代码锁住了某个对象,其他需要获取该锁(即被synchronized修饰)的代码块需要被执行,必须获取该对象的锁,即等到synchronized释放锁(其实就是改代码块执行完),它才有可能被执行,只是当synchronized修饰代码块时,必须显式地指出它锁定了哪个对象而已。上代码: 代码五: publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest3test3=newTest3();newThread(newRunnable(){publicvoidrun(){try{ test3.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start();newThread(newRunnable(){publicvoidrun(){ test3.thirdMethod(); } }).start(); } }classTest3{publicvoidfirstMethod()throwsInterruptedException{synchronized(this){ System.out.println("firstMethod"); Thread.sleep(2000); } }publicvoidthirdMethod(){synchronized(this){ System.out.println("thirdMethod"); } } } 上面代码和代码二五执行效果任何区别,实现的功能也是一样的。 当然,与直接修饰方法相比,synchronized修饰代码块时,this可以换成其他对象,我们锁定对象的代码块也可以粒度更小。 好,上面一堆废话其实归根到底都是说明一个道理:synchronized修饰的代码,它表示锁住了某个对象,被该关键字修饰的其他线程(强调其他线程,稍后讲为什么)的方法如果要执行,也必须得到该锁,即synchronized代码块执行完。 上面强调其他线程的意思是,如果同一个线程中被synchronized的方法,则无需获取该锁,这是合理的,具体看下面例子估计就明白我在说什么了: publicclassSynchronizedTest1{publicstaticvoidmain(String[]argStrings){finalTest4test4=newTest4();newThread(newRunnable(){publicvoidrun(){try{ test4.firstMethod(); }catch(InterruptedExceptione){ e.printStackTrace(); } } }).start(); } }classTest4{publicsynchronizedvoidfirstMethod()throwsInterruptedException{ System.out.println("firstMethod"); Thread.sleep(2000); secondMethod(); }publicsynchronizedvoidsecondMethod(){ System.out.println("secondMethod"); } } 结果是:firstMethod secondMethod 好吧,我也觉得我在讲废话,确实这是显而易见的结果:被synchronized修饰的方法如果互相嵌套调用,同一条线程中并不需要等待上一个synchronized块执行完,毕竟,这样会陷入死循环。获取锁或者说锁定对象,是针对不同线程而言的。 二、synchronized原理详解 1、首先理解几个锁概念:对象锁(也就重量锁),轻量锁,偏向锁 A、对象锁(重量锁) 在多线程环境下,大多数(后面会将为什么是大多数修饰)每个对象都会有一个monitor对象(关于monitor具体可以查看jdk api文档),这个对象其实就是上面我们解释synchronized关键字时对应的锁。这个对象锁负责管理所有访问该对象的线程,具体管理模型图可以参考下面的示意图: 对于访问该对象的线程,并发情况下,没有抢到锁(即对象访问权)的线程,会被monitor丢进list这个队列进行等候(当然,自旋锁情况例外,后面会具体讲解什么卵是自旋锁)。而所谓的公平锁与非公平锁,就是在notify唤醒list中的等候线程时,list中的线程是按照排队顺序获得锁还是一起抢该对象的锁,前者是公平的,先等候的线程先获得锁;后者则是不公平的,抢不抢到锁,和线程等待时间无关,与运气有关。 B、轻量锁 显然,重量锁对于每个对象都要维护一个monitor对象,开销肯定是挺大的,jvm对此进行了一些优化,这便是轻量锁出现的原因。 轻量锁大概是这样一种概念:尽管程序是多线程环境,但是如果访问当前对象的,该对象并不会new一个monitor,而是在对象的头部用一个标识字段(貌似是两位的二进制数)表示锁,这个就是轻量锁。在线程尝试访问该对象时,该线程会将当前线程私有空间中的对应锁标识字拷贝到对象头部,如果修改成功,表示只有一条线程访问该对象该对象继续采用轻量锁;如果发现轻量锁已经被其他线程占有锁定,jvm会将轻量锁升级为重量锁。 C、偏向锁 偏向锁是比轻量锁更轻量的锁:当jvm发现当前程序是但线程运行时,变会对对象采取偏向锁,当然,一旦发现有synchronized多线程执行情形,jvm会把偏向锁上升为轻量锁。 2、synchronized如何实现 了解了上面提到的几个锁的概念后,理解synchronized实现原理就非常容易了。 在多线程环境下,对象对应的monitor管理着需要访问该对象的所有线程,monitor中会有个变量存储synchronized获取次数,在一个线程的中的某个synchronized代码块获取monitor之后,该变量数加一,对于synchronized嵌套情形一样如此:有多少个synchronized,对应的变量值就是多少,对于其他线程如果想获得monitor,必须等到当前占有monitor线程的所有synchronized块均执行完,每执行完一个synchronized块,标识变量值减一,变为0时,其他线程就可以开始抢锁了。 所以,所有的管理工作均由monitor完成,它是synchronized实现的核心。 3、其他知识的补充 A、自旋锁 上面提到,monitor在管理每个阻塞线程的时候,会把它们放进一个队列里面,这是针对非自旋锁,当monitor被设置为自旋锁锁时,线程不会被挂起放进队列,而是在做循环,直到获取monitor的访问权。所以自旋锁有什么存在必要呢?其实,线程的挂起和唤醒的调度过程是需要耗费cpu的,当线程持有锁的时间非常短时,我们没必要将等待线程挂起,这样会导致线程的频繁挂起和唤醒,浪费了cpu资源。当然,自旋锁中线程在做循环时肯定也会消耗资源的,所以如何选择还是要衡量调度线程花费大还是线程原地循环花费大。 另外,针对上面情形,还有一种锁叫做自适应自旋锁,它大概解决了上面提到的一些问题; B、自适应自旋锁 自适应自旋锁其实就是在自旋锁的基础上加了个自旋数的计数:当循环了一定次数后,该线程还没有获取锁时,它就被丢进队列里挂起。

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册