如何设计java线程安全类_如何设计线程安全的Java程序

什么是线程安全的(thread-safe)?

在java中,线程安全的指的是代码可以在并发的或者多线程的环境下安全的使用或者共享,并且它们都将按照期望的方式运行。任何代码,类或者对象,如果它们在并发的环境中运行表现出的行为与在非并发环境下表现出的行为不一致,那么它们就不能被称为线程安全的。

本片文章不会非常仔细的介绍线程安全或者Java中的异步处理,我们将通过几个例子来帮助你理解什么是线程安全的然后告诉你如何让你的代码线程安全。

一个non-thread-safe的例子

public class Counter {

private int count;

/*

* 这个方法不是线程安全的,因为++操作不是原子操作

*/

public int getCount(){

return count++;

}

} 上面的例子不是线程安全的,因为++(自增操作)不是一个原子操作(atomic operation),而是会被拆分成读、更新和写操作(read,update,write)三部分,如果多个线程大约在同一时刻调用getCount()方法,这三个操作可能会互相重合(coincide)或者重叠(overlap),比如:当thread1正在更新数据,thread2此时读取数据,那他将会获得原来的旧数据,最后的结果就是thread2会覆盖掉thread1对数据的增加操作,结果就是:一个数据被丢失了,就是因为程序是并发调用的。

如何在Java中实现线程安全?

要使上面的方法线程安全,可以有很多种方式:

1)使用synchronized关键字来锁定getCount方法,以保证同一时刻只有一个线程可以访问getCount方法,这样做就能避免重合(coincide)或者重叠(overlap)问题。

2)使用AutomicInteger,这样就将++变成了原子操作,因为原子操作是线程安全的,这样做还节省了额外的同步操作的开销。

下面是一个实现线程安全的例子:

public class Counter {

private int count;

AtomicInteger atomicCount = new AtomicInteger( 0 );

/*

* 现在这个方法是线程安全的,因为增加了synchronized

*/

public synchronized int getCount(){

return count++;

}

/*

*这个方法是线程安全的,因为count的增加操作是原子操作

*/

public int getCountAtomically(){

return atomicCount.incrementAndGet();

}

} 关于Thread-Safe的一些重要的点:

这些点在你写线程安全的程序的时候是很有用的,而且也能帮你避免一些很严重的并发问题,比如:竞争条件(race condition)或者死锁

1)不可变的对象(immutable objects)默认就是线程安全的,因为它们的状态一旦创建就不能被改变。由于字符串在Java中就是不可变的,所以它们原本就是线程安全的(关于不可变对象,后期会有相关文章进行说明)。

2)只读的或者被final修饰的变量也是线程安全的。

3)锁机制在Java中是一种实现线程安全的方式。

4)静态变量如果没有被正确的synchronized,那么它将成为线程安全问题的主要原因。

5)Java中的一些线程安全的例子:Vector, Hashtable, ConcurrentHashMap, String等。

6)Java中的原子操作是线程安全的,比如从内存中读取一个32位的int值是线程安全的,因为它是原子操作,所以不会与其他线程交错。

7)局部变量也是线程安全的,因为每一个线程都会有属于她自己的一份拷贝。使用局部变量是一种很好的实现线程安全的方式。

8)为了实现线程安全,尽可能地减少多个线程中对象的共享。

9)volatile关键字可以用来指示线程不缓存该变量而是直接从主内存中读取,也可以指示JVM不从多线程的角度来重新排序或者优化代码(not to reorder or optimize code from threading perspective)。

以上就是本文介绍的一些内容。

线程安全是一个比较难以掌握的概念,为了确定程序是否线程安全你需要考虑多并发的情况,另外JVM为了会对代码进行优化,而优化的过程就会涉及到对代码的重新排序,所以看起来是串行的程序在开发环境中运行良好,但并不能保证在生产环境中会同样良好,因为JVM会尽最大可能的进行调整,从而进行一些代码重排序和优化,这样就会导致线程安全的问题。

----------------------------------------------------------------

小人不才,如有问题,欢迎各位不吝赐教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327762.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中的AIO

转载自 java中的AIO简介jdk7中新增了一些与文件(网络)I/O相关的一些api。这些API被称为NIO.2,或称为AIO(Asynchronous I/O)。AIO最大的一个特性就是异步能力,这种能力对socket与文件I/O都起作用。AIO其实是一种在读写操作结束之前允许进行其他操作的I/O…

Mybatis+MySQL动态分页查询数据经典案例(含代码以及测试)

最近在用Mybatis做项目的时候遇到了不少问题,今天我就在这和大家分享一下,稀稀拉拉的研究了两天,终于搞好了! 开发人员:1111 开发软件:Myeclipse 用到的框架技术:Mybatis 数据库:MyS…

细说ASP.NET Core静态文件的缓存方式

一、前言 我们在优化Web服务的时候,对于静态的资源文件,通常都是通过客户端缓存、服务器缓存、CDN缓存,这三种方式来缓解客户端对于Web服务器的连接请求压力的。 本文指在这三个方面,在ASP.NET Core中静态文件的实现过程和使用方法…

金田项目的总结

一个搜索框对手机、姓名、内容进行搜索 <select id"list" parameterType"java.lang.String" resultMap"BaseResultMap">select<include refid"Base_Column_List"/>from user_backstagewhere 11 and is_deletedN<if te…

18000 6c java_面向ISO18000-6C协议的无源超高频射频识别标签芯片设计

摘要&#xff1a;This paper presents a new fully integrated wide-range UHF passive RFID tag chip design that is compatible with the ISO18000-6C protocol. In order to reduce the die area, an ultra-low power CMOS voltage regulator without resistors and an are…

Vue异步组件

转载自 Vue异步组件 在大型应用中&#xff0c;我们可能需要将应用分割成小一些的代码块&#xff0c;并且只在需要的时候才从服务器加载一个模块。为了简化&#xff0c;Vue 允许你以一个工厂函数的方式定义你的组件&#xff0c;这个工厂函数会异步解析你的组件定义。Vue 只有在…

文章中文字乱码问题解决办法集合

乱码问题 测试步骤&#xff1a; 1、我们可以在首页编写一个提交的表单 <form action"/e/t" method"post"><input type"text" name"name"><input type"submit"> </form>2、后台编写对应的处理类 …

.NET开源两年之后社区贡献如何

微软在 2014 年开源了 .NET 核心框架&#xff0c;欢迎社区贡献代码。2015 年&#xff0c;一位 .NET 开发者分析了开源一年之后的社区贡献。2016 年年底又到了&#xff0c;这位开发者再次发表文章&#xff0c;分析了 .NET 开源两年之后的情况。 这一次他分析了 15 个 .NET 开源项…

java把控件跑挂了_Java代码动态修改 ConstraintLayout 内控件布局的辅助类

##上图ConstraintUtil.javaimport android.support.annotation.IdRes;import android.support.constraint.ConstraintLayout;import android.support.constraint.ConstraintSet;import android.transition.TransitionManager;/*** Created by xiaolei on 2017/9/8.*/public cla…

json vs obj

var obj {a: Hello, b: World}; //这是一个对象&#xff0c;注意键名也是可以使用引号包裹的 var json {"a": "Hello", "b": "World"}; //这是一个 JSON 字符串&#xff0c;本质是一个字符串在 JavaScript 语言中&#xff0c;一切都…

Vue动态组件

转载自 Vue动态组件 在动态组件上使用 keep-alive 我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件&#xff1a; <component v-bind:is"currentTabComponent"></component> 当在这些组件之间切换的时候&#xff0c;你有时会想保持这些组…

ASP.NET Core Kestrel部署HTTPS

ASP.NET Core配置 Kestrel部署HTTPS。现在大部分网站已经部署HTTPS&#xff0c;大家对于安全越来越重视。 今天简单介绍一下ASP.NET Core 部署HTTPS&#xff0c;直接通过配置Kestrel。大家也可以通过前置Nginx来部署HTTPS。 下面直接进入正题。 新建项目并添加引用 新建一个ASP…

Mybatis+mysql动态分页查询数据案例——分页工具类(Page.java)

package cn.bdqn.mhouse.util;import java.util.ArrayList; import java.util.List;import cn.bdqn.mhouse.entity.House;/*** * * 项目名称&#xff1a;mhouse * 类名称&#xff1a;Page * 类描述&#xff1a; 分页的工具类 * 创建人&#xff1a;Mu Xiongxiong …

JSON 和 JavaScript 对象互转

JSON 和 JavaScript 对象互转 要实现从JSON字符串转换为JavaScript 对象&#xff0c;使用 JSON.parse() 方法&#xff1a; var obj JSON.parse({"a": "Hello", "b": "World"}); //结果是 {a: Hello, b: World}要实现从JavaScript 对…

java 时钟 算法分析_java实现时钟方法汇总

import java.awt.Dimension;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.Timer;import java.util.TimerTask;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;//第一种比较推荐&…

Java IO: 网络

转载自 Java IO: 网络译文链接 作者: Jakob Jenkov 译者: 李璟(jlee381344197gmail.com) 校对&#xff1a;方腾飞 Java中网络的内容或多或少的超出了Java IO的范畴。关于Java网络更多的是在我的Java网络教程中探讨。但是既然网络是一个常见的数据来源以及数据流目的地&#xf…

配置phython环境

参考资料 https://www.runoob.com/python/python-install.html https://www.cnblogs.com/huangbiquan/p/7784533.html Python下载 Python最新源码&#xff0c;二进制文档&#xff0c;新闻资讯等可以在Python的官网查看到&#xff1a; Python官网&#xff1a;https://www.py…

ASP.NET Core 之 Identity 入门(三)

前言 在上一篇文章中&#xff0c;我们学习了 CookieAuthentication 中间件&#xff0c;本篇的话主要看一下 Identity 本身。 最早2005年 ASP.NET 2.0 的时候开始&#xff0c; Web 应用程序在处理身份验证和授权有了很多的变化&#xff0c;多了比如手机端&#xff0c;平板等&…

玩物得志Java笔试题_代码规范利器-CheckStyle

本期内容分为五个部分&#xff0c;阅读时长预估7分钟&#xff1a;使用背景CheckStyle使用意义CheckStyle安装与使用CheckStyle检查配置示例落地使用情况及效果使用背景玩物得志目前还处在一个狂奔业务的时期&#xff0c;开发一般都全力支撑业务的快速奔跑&#xff0c;没有太多的…