使用多线程就可能会存在线程安全的问题。很多 java 程序员对写多线程都很挣扎,或者仅仅理解那些是线程安全的代码,那些不是。这篇文章我并不是详述线程安全,详述同步机制的文章,相反我只是用一个简单的非线程安全的代码例子引领大家,然后重点是去理解什么是线程安全,以及怎样使代码变得线程安全。

好了,下面我们先来看一个非线程安全的代码,可以尝试找找为什么非线程安全?

/*
* 非线程安全类
*/  
public class Counter {
private int count;
 
public int getCount(){
       return count++;
   }
}

大家应该能看得出来,上面代码是非线程安全的,因为 ++ 操作不是原子操作,读取、更新、写回的时候可能会出问题。

比如现在有多个线程同时访问 getCount() 方法,那么这些线程可能同时操作 count ,部分结果出现重叠。例如,Thread 1 正在更新 count,Thread 2 读取 count,但是仍然是获取到旧的值,那么最后Thread 2 就会覆盖掉 Thead 1 的更新,所以并发环境下我们要考虑 ++ 操作的原子性。

在 Java 编程中,有许多方式去编写线程安全的代码:

1)、使用 synchronized 关键字,synchonized 可以 lock  getCount() 方法,某个时刻只有一个线程可以执行它,也就实现了线程安全

2)、使用原子的 Integer,原子的 Integer 可以保证 ++ 操作的原子性

好了,我们了看看线程安全版本的 Counter

public class Counter {
    private int count;
    AtomicInteger atomicCount = new AtomicInteger( 0 );
  
   /*
*1、synchronized 所以线程安全
*/
    public synchronized int getCount(){
        return count++;
    }
  
    /*
     * 2、原子增长的操作,所以线程安全
     */
    public int getCountAtomically(){
        return atomicCount.incrementAndGet();
    }
}
 
java 线程安全比较重要的点:
 
在 java 编程中,记住这些关键点可以帮你避免一些严重的并发问题,比如条件竞争或死锁。
1)、不可变对象默认是线程安全的,因为他们一旦被创建就不会被修改。比如 String 是不可变对象,是线程安全的。
 
2)、只读、final 类型的变量也是线程安全的
 
3)、锁也是一种线程安全的方式
 
4) 、static 变量,如果没有被恰当的使用同步,也会引发线程安全问题
 
5)、使用线程安全的类: Vector, Hashtable, ConcurrentHashMap, String etc.
 
6)、原子操作是线程安全的 reading a 32 bit int from memory because its an atomic operation it can't interleave with other thread.
 
7) 、本地变量也是线程安全的,因为每个线程都有自己的变量 copy.使用本地变量是一种保证代码线程安全的好方法。(ThreadLocal)
 
8)、 多线程之间的共享对象尽可能的少,也就尽可能的避免线程安全的问题
 
9) 、Volatile 关键字
 
 
好了,以上就是所有的关于编写线程安全类或代码和避免并发问题的要点。老实说,线程安全是有点难掌握的概念,你需要去考虑并发,进而看代码是否线程安全。
当然 jvm 也可以重排序代码,实现自己调优。但是相同的代码在开发环境正常不一定能保证在线上也正常。因为 jvm 会去自我调优,重排序等操作去优化代码,这些也可能会生成线程安全的问题。
 

怎样去写线程安全的代码(Java)的更多相关文章

  1. 如何写出无法维护的代码(JAVA版)

    程序命名(针对那些不能混淆的代码) 容易输入的名字.比如:Fred,asdf 单字母的变量名.比如:a,b,c, x,y,z,或者干脆上中文比如(阿隆索肯德基) 有创意地拼写错误.比如:SetPint ...

  2. Java线程运行轨迹-代码追踪与定位

    今天在写程序时,想到一个问题,当我的程序出异常的时候,控制台输出信息中,明确指出了出现异常的位置,并详细列举了函数的调用层次关系,它是怎么做到的. 竟然想到了这个问题,就去查看了源代码,不过没点几下, ...

  3. Java认证:JavaRunnable线程编写接口代码

    Java认证:JavaRunnable线程编写接口代码.JavaRunnable线程如何才能更好的适应目前的编程环境呢?下面我们就看看如何才能更好的进行相关环境.希望下面的文章对大家有所帮助.Java ...

  4. 手写代码 - java.util.Arrays 相关

    1-拷贝一个范围内的数组 Arrays.copyOfRange( array, startIndex, endIndex); include startIndex... exclude endInde ...

  5. 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结

    虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...

  6. 《写给大忙人看的Java SE 8》——Java8新特性总结

    阅读目录 接口中的默认方法和静态方法 函数式接口和Lambda表达式 Stream API 新的日期和时间 API 杂项改进 参考资料 回到顶部 接口中的默认方法和静态方法 先考虑一个问题,如何向Ja ...

  7. 学习 Doug Lea 大神写的——Scalable IO in Java

    学习 Doug Lea 大神写的--Scalable IO in Java 网络服务 Web services.分布式对象等等都具有相同的处理结构 Read request Decode reques ...

  8. 自己动手写线程池——向JDK线程池进发

    自己动手写线程池--向JDK线程池进发 前言 在前面的文章自己动手写乞丐版线程池中,我们写了一个非常简单的线程池实现,这个只是一个非常简单的实现,在本篇文章当中我们将要实现一个和JDK内部实现的线程池 ...

  9. 分页 工具类 前后台代码 Java JavaScript (ajax) 实现 讲解

    [博客园cnblogs笔者m-yb原创, 转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708]http ...

随机推荐

  1. IIS7.0上传在大小限制

    修改 IIS7的上传文件大小限制的方法: 1.打开IIS管理器,并定位于想要修改限制的网站 2.双击右侧窗口中的asp图标 3.展开最下面那个“限制属性”,将最下面的“最大请求实体主体限制”右边属性框 ...

  2. Java 常见面试题(一)

    1)什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件.Java被设 ...

  3. Configuration Reference In Vue CLI 3.0

    Configuration Reference This project is sponsored by  #Global CLI Config Some global configurations ...

  4. javascript 事件流的应用之 addEventListener

    原始需求:防止按钮短时间内高频率触发点击事件,由于重复提交导致的业务异常. 图: demo: <!DOCTYPE html> <html lang="en" di ...

  5. EditText输入小数

    edtValue.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);

  6. Python 单列

    1.__new__内置方法 在对类进行实例化时自动执行 功能1:为对象分配空间 功能2:返回空间的引用 2.单列实现方法 class MusicPlayer: # 记录对象内存引用,初始值为None ...

  7. 5. Longest Palindromic Substring - Unsolved

    https://leetcode.com/problems/longest-palindromic-substring/#/description Given a string s, find the ...

  8. 【转】centos7 搭建etcd集群

    转自http://www.cnblogs.com/zhenyuyaodidiao/p/6237019.html 一.简介 “A highly-available key value store for ...

  9. 2018.11.08 NOIP模拟 班车(倍增+dfs+bit)

    传送门 对于每个点离线处理出向上走2i2^i2i班车到的最上面的点. 然后每个询问(u,v)(u,v)(u,v)先把(u,v)(u,v)(u,v)倍增到刚好走不到lcalcalca的情况(有一个点如果 ...

  10. 2018.11.01 NOIP训练 cost数(搜索+容斥原理)

    传送门 唉考试的时候忘记剪倍数的枝了666666分滚粗. 其实就是一直取lcmlcmlcm搜索,然后容斥原理统计就行了. 代码