Java多线程中static变量的使用

摘要:
(1) 静态变量:线程不安全1.静态变量:使用Static关键字定义的变量。静态修饰成员变量和成员方法独立于类的任何对象。因此,可以在创建静态对象之前访问该对象,而不引用任何对象。静态成员变量和用public修饰的成员方法本质上是变量和全局方法。在声明其类的对象时,不会生成静态变量的副本,但该类的所有实例都共享同一个静态变量。

线程,是我们项目中绕不过的重点领域。提到线程,就常会听到线程安全的术语。那什么是线程安全呢?通俗点说,就是线程访问时不产生资源冲突。其实,这是一个有点难以定义的概念,不是很容易让人一听就懂的概念。“一个类可以被多个线程安全调用就是线程安全的”《Java并发编程实践》。

    来说说静态变量、实例变量、局部变量在多线程下的安全问题吧!

    (一)静态变量:线程非安全

   1、静态变量:使用static关键字定义的变量。static可以修饰变量和方法,也有static静态代码块。被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

    用public修饰的static成员变量和成员方法本质是变量和全局方法,当声明它的类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。

    2、静态变量使用的场景:

    (1)对象间共享值时

    (2)方便访问变量时

    3、静态方法使用注意事项:

    (1)不能在静态方法内使用非静态变量,即不能直接访问所属类的实例变量;

    (2)不能在静态方法内直接调用非静态方法;

    (3)静态方法中不能使用this和super关键字;

    4、验证静态变量的线程安全性:

    (1)从程序执行的图中我们可以看出,执行结果中有错误数据,证明了静态变量是存在资源冲突问题的。

    (2)程序运行结果图:

Java多线程中static变量的使用第1张

  5、结论:静态变量也称为类变量,属于类对象所有,位于方法区,为所有对象共享,共享一份内存,一旦值被修改,则其他对象均对修改可见,故线程非安全。

    (二)实例变量:单例时线程非安全,非单例时线程安全

    1、实例变量:实例变量属于类对象的,也就是说,属于对象实例私有,在虚拟机的堆中分配。

    2、验证实例变量的线程安全性:

    (1)从程序截图中,我们可以看到,当为单例模式时,会产生资源冲突,当非单例模式时,则不会产生线程冲突。

    (2)程序运行结果图:

    图1:

Java多线程中static变量的使用第2张

   图2:

Java多线程中static变量的使用第3张

 3、结论:实例变量是实例对象私有的,系统只存在一个实例对象,则在多线程环境下,如果值改变后,则其它对象均可见,故线程非安全;如果每个线程都在不同的实例对象中执行,

则对象与对象间的修改互不影响,故线程安全。

    (三)局部变量:线程安全

     1、局部变量:定义在方法内部的变量。

     2、验证局部变量的安全性:

    (1)从程序截图中可以看出,局部变量在多线程下没有产生资源冲突的问题

    (2)程序运行结果图:

Java多线程中static变量的使用第4张

3、结论:每个线程执行时都会把局部变量放在各自的帧栈的内存空间中,线程间不共享,故不存在线程安全问题。

    (四)静态方法的线程安全性

     1、静态方法中如果没有使用静态变量,则没有线程安全的问题;

          静态方法内的变量,每个线程调用时,都会新创建一份,不会公用一个存储单元,故不存在线程冲突的问题。

总结:

1. java在执行静态方法时,会在内存中拷贝一份,如果静态方法所在的类里面没有静态的变量,那么线程访问就是安全的,比如在javaee中服务器必然会多线程的处理请求此时如果设计全局需要调用的静态方法,可用此种设计。

2. java在执行静态方法时,如果使用静态变量,同时类的函数设计时使用到了静态数据,最好在调用函数时使用synchronized关键字,否则会导致数据的不一致行。

3. 加静态全局的变量,在多线程访问下定会出现数据的不一致行,最好使用synchronized关键字,确保数据的一致性,典型的代表就是单例模式。

4. java是线程安全的,即对任何方法(包括静态方法)都可以不考虑线程冲突,但有一个前提,就是不能存在全局变量。如果存在全局变量,则需要使用同步机制。

加入synchronized关键字的静态方法称为同步静态方法。
在访问同步静态方法时,会获取该类的“Class”对象,所以当一个线程进入同步的静态方法中时,线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。这个其实就是操作系统中的用信号量实现进程的互斥与同步问题,如果涉及在同一个类中有多个静态方法中处理多线程共享数据的话,那就变成用信号量解决生产者-消费者问题。也就是说,静态方法是一份临界资源,对静态方法的访问属于进入临界区;对静态变量的修改是一份临界资源,对静态变量的修改属于进入临界区。

转自:https://www.cnblogs.com/panchanggui/p/9680694.html

免责声明:文章转载自《Java多线程中static变量的使用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IDEA文件查找功能失效(ctrl+shift+N)pytest测试报告allure下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

解决sql 语句中truncate语句不支持变量的问题

sql 语句中truncate语句不支持变量的问题,就像Sql2000中select top 后面不支持变量一眼,那么融会贯通,此处也可采用动态Sql语句来解决 create proc sp_ClearDataByTableName @tablename Char(20) as declare @a varchar(20) set @a=@tablenam...

SQL中declare变量的作用域(续)一些问题

在上次讨论了declare变量的作用域以后我们继续深入谈论一下,准确的说是我有些疑惑想跟大家讨论,有高手明白的话指点一下。 关于作用域的谈论:http://www.cnblogs.com/breezeli/archive/2010/04/16/1713308.html 这个问题不太好解释,大家看一段代码,在循环中定义表变量。 注意 代码使用Northw...

前端视频播放组件 vue-dplayer

1.安装 cnpm install vue-dplayer -S 2.在main.js中导入 import VueDPlayer from 'vue-dplayer'; import 'vue-dplayer/dist/vue-dplayer.css'; Vue.use(VueDPlayer); 3.使用vue-dplayer组件: 1 <tem...

杂七杂八——Name与x:Name的关系

小序: 如果想用Google搜包含冒号的内容怎么办?比如我想搜x:Name这个字符串…… 原来,应该是这样——x::Name 这世道,连搜索也要加转义,全民程序员,要不要人活了? 正文: 从第一天学习XAML语言开始,我就一直没分清为什么对于一个XAML标签既可以设置它的Name又可以设置它的x:Name。问过一些同事,大家好像对这种比较孔乙己的问题不太...

“C语言” 读书札记(六)之[Linux下C语言编程环境Make命令和Makefile] 川山甲 博客园

“C语言” 读书札记(六)之[Linux下C语言编程环境Make命令和Makefile] - 川山甲 - 博客园 “C语言” 读书札记(六)之[Linux下C语言编程环境Make命令和Makefile]介绍一般程序都是由多个源文件编译链接而成的,这些源文件的处理步骤通常由Makefile文件管理。用途make工具用来进行协调的工具,可以根据程序模块的修改情...

《Win32多线程程序设计》学习笔记 第10章 MFC 中的线程

如果要在MFC程序中产生一个线程,而该线程将调用MFC函数或者使用MFC的任何数据,那么你必须以AfxBeginThread()或者CWinThread::CreateThread()来产生这些线程,理由同C runtime library. 在MFC中启动一个worker线程 如果线程调用了GetMessage或者CreateWindow之类的函数,消息...