从Linux的errno到Java的ThreadLocal

Posted awzh2020

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Linux的errno到Java的ThreadLocal相关的知识,希望对你有一定的参考价值。

Linux里的errno


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

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

errno示例:

技术图片

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

技术图片

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

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

技术图片

使用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就行了。

技术图片

 

Java的ThreadLocal


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

技术图片

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

自己实现一个ThreadLocal


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

技术图片

以上是关于从Linux的errno到Java的ThreadLocal的主要内容,如果未能解决你的问题,请参考以下文章

linux 中的errno 和 strerror(errno)

Linux 系统错误码 errno 剖析

C Linux ioctl TCGETS 和 TCSETS errno 25

Linux系统中errno对应的中文意思 errno.h

Linux errno错误码

Linux errno