打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
某种特殊场景下JDK编译器对 Java 基本类型的封包操作!

本文描述了在某种特殊场景下JDK编译器对 Java 基本类型的封包操作。

其原理非常简单,但是现象却非常 非常的迷惑人。可以让我们从另外一个角度看待jdk对基本类型的封包。

本文代码的原意是想找到一种当future超时后,可以尽量快的终止掉还在运行的future(事实上,future超时后(在主线程抛出超时异常后),future线程并不会停止,直到它运行结束,自然消亡。)

先上代码:

主函数:

Java代码

  1. package thread.InteruptTest;

  2. import java.io.IOException;

  3. import java.util.concurrent.*;

  4. /**

  5. * 通过线程池 开启一个线程去处理

  6. * 模拟请求来时,开启一个线程处理请求的场景

  7. * Created with IntelliJ IDEA.

  8. * User: liukunyang

  9. * Date: 13-12-13

  10. * Time: 上午9:51

  11. * To change this template use File | Settings | File Templates.

  12. */

  13. public class Main {

  14. public static void main(String[] args) throws Exception {

  15. ThreadPoolExecutor exec = new ThreadPoolExecutor(0, 10,

  16. 5, TimeUnit.SECONDS,

  17. new LinkedBlockingQueue(),new ThreadPoolExecutor.CallerRunsPolicy());

  18. TestThread tt = new TestThread();

  19. exec.submit( tt );

  20. //保持主线程存货, console端观察结果

  21. System.in.read();

  22. }

  23. }

再看TestThread类:

Java代码

  1. package thread.InteruptTest;

  2. import java.util.concurrent.*;

  3. /**

  4. *

  5. *

  6. * 再启动一个线程池去提交 future 任务,该线程会在等待5秒后尝试获取future结果

  7. * 并捕获future的超时异常。 最后设置future的 cancel 标志位,如果运行future的线程检查到标志位

  8. * 改变就可以停止掉自己。

  9. * Created with IntelliJ IDEA.

  10. * User: liukunyang

  11. * Date: 13-12-13

  12. * Time: 上午9:55

  13. * To change this template use File | Settings | File Templates.

  14. */

  15. public class TestThread extends Thread {

  16. private ThreadPoolExecutor threadPoolExecutor =

  17. new ThreadPoolExecutor(0, 10, 5, TimeUnit.SECONDS,

  18. new LinkedBlockingQueue(),new ThreadPoolExecutor.CallerRunsPolicy());

  19. ;

  20. @Override

  21. public void run() {

  22. ThreadLocal th = new ThreadLocal();

  23. DivideFuture df = new DivideFuture();

  24. final Future future = threadPoolExecutor.submit(df);

  25. try {

  26. //5秒后在超时,

  27. //给子线程5秒的时间打印 变量isC1,isC2,isC3的值

  28. System.out.println( '1'+future.get(5,TimeUnit.SECONDS) );

  29. } catch (InterruptedException e) {

  30. e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

  31. } catch (ExecutionException e) {

  32. e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

  33. } catch (TimeoutException e) {

  34. System.out.println('超时拉');

  35. }finally {

  36. df.cancel();

  37. future.cancel(true);

  38. }

  39. }

  40. }

DivideFuture 类:

Java代码

  1. package thread.InteruptTest;

  2. import java.util.concurrent.Callable;

  3. /**

  4. * 使用了三种不同类型的标志位,用来更好的说明 jdk对基本类型的封包操作

  5. * 使用threadlocal的原因是 如果call 方法再调用了其他bean 的其他方法 仍然可以通过threadlocal 获取到cancel的标志位 这里为了简单没有增加调用其他方法的代码

  6. * 但是不影响说明原理

  7. * Created with IntelliJ IDEA.

  8. * User: liukunyang

  9. * Date: 13-12-13

  10. * Time: 上午11:05

  11. * To change this template use File | Settings | File Templates.

  12. */

  13. public class DivideFuture implements Callable {

  14. private ThreadLocal thISC1 = new ThreadLocal();

  15. private ThreadLocal thISC2 = new ThreadLocal();

  16. private ThreadLocal thISC3 = new ThreadLocal();

  17. private boolean isC1;

  18. private Boolean isC2;

  19. private RichBoolean isC3;

  20. /**

  21. * 修改isC1,isC2,isC3的标志位

  22. */

  23. public void cancel(){

  24. isC1 = true;

  25. isC2 = true;

  26. isC3.setValue(true);

  27. }

  28. @Override

  29. public Object call() throws Exception {

  30. //在线程调用时,再将isC初始化,

  31. //是的threadLocal取到的线程是执行该方法的线程

  32. isC1 = false;

  33. isC2 = false;

  34. isC3 = new RichBoolean(false);

  35. thISC1.set(isC1);

  36. thISC2.set(isC2);

  37. thISC3.set(isC3);

  38. // 每隔一秒获取一下标志位的值

  39. for(int i=0; i<10 ;="">

  40. try{

  41. Thread.sleep(1000);

  42. }catch(Exception e){

  43. }

  44. System.out.println(i);

  45. System.out.println( '变量 isC1 的值:' + isC1 );

  46. System.out.println( '变量 isC1 通过ThreadLocal获取的值:' + thISC1.get() );

  47. System.out.println( '变量 isC2 的值:' + isC2 );

  48. System.out.println( '变量 isC2 通过ThreadLocal获取的值:' + thISC2.get() );

  49. System.out.println( '变量 isC3 的值:' + isC3 );

  50. System.out.println( '变量 isC3 通过ThreadLocal获取的值:' + thISC3.get() );

  51. }

  52. return 'this is callable';

  53. }

  54. }

最后是辅助bean:

Java代码

  1. package thread.InteruptTest;

  2. /**

  3. * Created with IntelliJ IDEA.

  4. * User: liukunyang

  5. * Date: 13-12-13

  6. * Time: 下午2:03

  7. * To change this template use File | Settings | File Templates.

  8. */

  9. public class RichBoolean {

  10. private boolean value;

  11. public RichBoolean(boolean value) {

  12. this.value = value;

  13. }

  14. public void setValue(boolean value) {

  15. this.value = value;

  16. }

  17. public boolean isValue() {

  18. return value;

  19. }

  20. }

猜猜打印的结果是啥?

注意红色和蓝色部分。

0

变量 isC1 的值:false

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:false

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

1

变量 isC1 的值:false

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:false

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

2

变量 isC1 的值:false

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:false

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

3

变量 isC1 的值:false

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:false

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

4

变量 isC1 的值:false

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:false

变量 isC2 通过ThreadLocal获取的值:false

超时拉

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

5

变量 isC1 的值:true

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:true

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

6

变量 isC1 的值:true

变量 isC1 通过ThreadLocal获取的值:false

变量 isC2 的值:true

变量 isC2 通过ThreadLocal获取的值:false

变量 isC3 的值:thread.InteruptTest.RichBoolean@5740bb

变量 isC3 通过ThreadLocal获取的值:thread.InteruptTest.RichBoolean@5740bb

想想为什么isC1,isC2中,future自身的变量变为了true 而他们对应的threadlocal中的值却还是false???????

难道是线程之间不能使用这种方式访问同一个变量?

那为什么isC3又是和我们想想的一样的?

其实仔细推导后发现原理非常简单

看看DivideFuture.class

内层的红色框中说明,我们cancel时是将isC2的变量重新赋值了,也就是说isC2指向了一个新的对象 而thISC2 里面还是老的值,所以他们打印出来的结果不同。

同理,isC1 = true 这句话因为jdk 封包操作的原因类似isC2也是重新new了一个对象,isC1指向了新对象,而thISC1中还是老对象。所以导致了上述的结果。

也算是对jdk封包,解包操作的一个新理解吧。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[细品java]ThreadLocal源码学习
ThreadLocal父子线程数据传递方案
详细领悟ThreadLocal变量
Java线程(篇外篇):线程本地变量ThreadLocal
Java多线程之隔离技术ThreadLocal源码详解
Java之ThreadLocal
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服