zoukankan      html  css  js  c++  java
  • 从Linux的errno到Java的ThreadLocal

    Linux里的errno


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

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

    errno示例:

    wKioL1WbuPjQ9_gzAAHrJFspGzI545.jpg

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

    wKiom1Wbt2CSHc8DAAC4FjSCW0c854.jpg

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

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

    wKioL1WbuZuyhJVTAAJJJiKqJHo234.jpg

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

    wKiom1Wbudzhz-3IAAUruAEgEOY812.jpg

    Java的ThreadLocal


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

    wKioL1WbvwTCsMG7AAI8sT9dyJo690.jpg

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

    自己实现一个ThreadLocal


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

    wKioL1WbwHKxdsl-AAJ3jZYOBEA724.jpg

  • 相关阅读:
    vscode常用插件
    2019前端面试总结
    用户注册登录的逻辑
    Vue项目各个文件夹的作用
    Gulp & webpack 配置详解
    Webpack 配置入门
    开始一个React项目(一)一个最简单的webpack配置
    资源加载过程
    关于Netty Pipeline中Handler的执行顺序问题
    解压版中文乱码问题MYSQL中文乱码
  • 原文地址:https://www.cnblogs.com/awzh2020/p/12598890.html
Copyright © 2011-2022 走看看