从Linux的errno到Java的ThreadLocal


在Linux下执行系统调用时,一般会有一个返回值表示成功或失败,但是这个值只说明了成功或失败,却没有说明是如何成功或失败的。

errno就是为了解决这个问题的,系统调用会把错误号设置为errno,我们通过错误号就能知道失败的原因。还可以使用strerror打印出这个错误号对应的字符串说明。老版本的Linux需要加上extern int errno,现在直接引入<errno.h>就行了.

errno示例:

从Linux的errno到Java的ThreadLocal

现在的问题来了。假如我有两个线程,代码如下:

从Linux的errno到Java的ThreadLocal

errno是一个全局变量,那么假如执行顺序为 1-1,2-1,1-2,2-2,线程1打印出的errno就是线程2的,这就是errno的问题,线程不安全。

但是测试很多次,结果都是正确的。虽然你用这个errno是当作一个全局变量的,但是实际上是个宏。用gcc -E将源代码的宏展开,可以看到,errno被替换成了一个函数。

从Linux的errno到Java的ThreadLocal

使用man errno查看对errno的解释,可以看到下面一句话:

       errno  is  defined  by  the ISO C standard to be a modifiable lvalue of
       type int, and must not be explicitly declared; errno may  be  a  macro.
       errno  is  thread-local;  setting  it in one thread does not affect its
       value in any other thread.

所以errno并不是一个全局变量,而是一个thread-local,每个线程都有一个。我们可以自己实现一个errno。

 

自己写一个errno


仅仅演示一下errno的基本原理,使用一个map存放各个线程的errno,而这个map的key就是threadId。系统调用执行完毕后,会将错误码写入此线程对应的errno中。代码中的系统调用是一个假系统调用,some_system_call()。

实际开发中,对于开发者,他实际上是看不到set_errno(),get_errno()这些函数的,他只需要取errno就行了。

从Linux的errno到Java的ThreadLocal

 

Java的ThreadLocal


Java的ThreadLocal和Linux的errno是一样的,只不过errno对开发者来说更简单一点,而且只能取,当作一个变量就行了。

从Linux的errno到Java的ThreadLocal

只定义了一个ThreadLocal,但是各个线程里的都不一样。

自己实现一个ThreadLocal


其实ThreadLocal也和上面我自己实现的errno类似,用了一个Map,感兴趣的可以去看一下jdk源码,我写了一个很简陋的MyThreadLocal,Java的ThreadLocal的原理大致就是这样的。直接将上面的代码的ThreadLocal替换成MyThreadLocal就可以运行,当然这个MyThreadLocal太简单,仅仅为了介绍原理。

从Linux的errno到Java的ThreadLocal

 

 

https://www.jianshu.com/p/cdaf9b91fd21

https://www.jianshu.com/p/38a85d1851bb

https://www.jianshu.com/p/07ce7190a097

上一篇:yum 安装时错误 Errno 14 Couldn't resolve host 解决办法


下一篇:mysql-MY SQL-错误代码:1010.删除数据库时出错(无法rmdir; errno:13)