GWA2 Java 增加多线程数据共享通道 globalData

令举国民众震惊的江苏徐州丰县铁链女(生育八孩女子)一事逐渐被消音( https://ufqi.com/news/ulongpage.3651.html?tit=仍留下徐州丰县生育八孩女子独自面对命运|舆论手札 ),今暂且不论。

GWA2 Java 最近被部署到一个金融类项目( 有福金融:https://ufqi.com/finance )上运行之后,持续遇到并发、数据同步、多进程多线程数据访问控制的挑战。在此前一篇的博客中,我们讨论了在数据同步时的数据加锁的过程细节:Synchronized同步Quque队列Concurrency并发与线程锁Lock ( https://ufqi.com/blog/gwa2-php-synchronized/ )。 今天继续这个话题,讨论 GWA2 Java 寄宿于 Apache Tomcat中多进程多线程编程及运行时环境下,如何实现对多线程间数据的隔离与共享。

前文记述,在Apache Tomcat 等容器中,实现对数据的安全管控的最好的方式是使用 Synchronized 同步机制,让程序单线程运行,但这很难在Application层面扩展处理能力。于是我们修改了规则,默认不再启用 synchronized同步机制在全局。这样 GWA2 Java 重新回到多进程多线程运行环境,并发扩展能力激增。随之而来的就是在多线程运行时环境下,数据的隔离与共享。
有些数据是需要隔离的,比如在多线程并发运行时环境下,当请求1被线程A接管的同时,请求2被线程B接管,如果不做数据隔离的话,在整个进程中的数据都会被重置为较后者进来的请求。
我们需要某种机制将请求的各种数据限制在线程内。

同时,有些数据又需要被共享,一个接口或进程启动后,总有一些全局性的设置或变量,需要能够在所有线程中被访问到。这又要求我们必需提供某种机制能够满足,在多线程环境下,对一些全局数据的读写访问,并保障这些数据是线程安全的(Thread-Safe)。

fig1.单线程与多线程运行时状态示意图

在一番分析和探索之后,我们对GWA2 Java做了如下改进和升级,以实现GWA2 Java从 “线程不安全—单线程安全—多线程安全” 的演进

1/3. 改进全局数据容器data的类型:用ConcurrentHashMap取代HashMap

脱胎于GWA2 PHP,我们始终认为需要一个全局性的数据容器,可以将任务/业务处理过程中所产生的数据临时存放起来,这个数据容器无疑类型是一个字典表之类。在GWA2 Java中,起初使用了 HashMap(非线程安全的),后来遇到数据同步问题后,使用Synchronized同步关键词得以临时解决。
再次的探索研究,我们认为是时候使用 ConcurrentHashMap替代HashMap 了,ConcurrentHashMap 对多线程有更好的支持,而且是Java原生的数据类型。
代价也是有的,毕竟ConcurrentHashMap在数据读写时,要处理线程锁的问题,因为在数据处理上开销更大,速度稍慢。
另外令人不好接受的是,ConcurrentHashMap不接受null空值,key或者value,都不行,这无疑对于痛恨Java null的开发者来说,将会更加多地要注意,存储data数据时,需要考虑到是否null的前置判断。

2/3. 改进多数全局变量的作用域,由对象类的作用域缩小到方法体的作用域

在前一节改动使用 ConcurrentHashMap 取代HashMap后,data容器的确是数据安全了,可请求数据在并发情况下被重写的问题仍在。这源于我们在 JSP文件中声明变量时,使用!感叹号这样的武器。

<%!HashMap data;%>
将会生成一个作用域为对象类的变量data
<%HashMap data%>
将会生成一个作用域为方法体的变量data

这其中的细节可能要参考Java Servlet相关技术规罚手册。

根据Apache Tomcat默认能够将每一个请求分发到一个线程处理的机制,结合fig1.中对多线程的描述,我们发现将数据容器data的作用域由对象类缩小到方法体内,是解决这个问题的答案。
这就解决了请求数据在多线程环境下的数据隔离问题,当GWA2 Java所需要的数据容器及其他多数变量都已经内置于线程内(register和stack区域),其数据自然是被完全隔离的了。

改动也是有代价的,当我们做这样的修改后,data这样的“全局”变量的作用域减少了,是为了线程间数据隔离,同时也阻碍了我们在任何代码块中访问和使用这些数据。
比如在一个自定义的方法体内,在此改动之前,可以直接读取和写入操作data, 而这次修改之后,将不能对data数据进行任何读取或写入操作。

3/3. 增加线程间数据共享通道 globalData

改进到前两步已经实现了多线程安全的GWA2 Java运行时环境保证。但我们还不满足于此,我们仍希望GWA保持整个套系的风格,在GWA2 PHP中,全局变量 data 始终是全局的,任何代码空间都可以访问到。
在2/3.改动之前, GWA2 Java也能够提供这种全局访问的便利性,那是以靠Synchronized同步机制提供了单线程环境。有没有可能在 2/3.多线程运行时环境下,也提供一个具有全局访问便利性的数据容器data?

答案是肯定的,我们为GWA2 Java增加了线程间数据共享通道 globalData.

通过之前第二步的改进我们知道,当使用!感叹号标记的变量声明时,即可声明一个作用域为对象类的变量(fig1.中的code和data区域),这个变量可以在所有线程可见,在当前对象类的所有方法体可见。
如果把它声明为ConcurrentHashMap,其自身数据将是线程安全的,同时如果再进一步提供某种机制,保证每个线程都能够通过它读取到线程Id相关的数据,则又实现了线程间的数据差异。
沿着这个思路,我们定义GWA2 Java多线程间数据共享通道 globalData 。

<%!ConcurrentHashMap globalDataHolder;%>
<%globalDataHolder = new ConcurrentHashMap();%>
<%!
//- write/read global data into/from a thread-safe holder, 09:18 2022-02-24
//- write
public static void globalData(String key, Object value){ .
String threadDataKey = “GWA2-” + ProcessHandle.current().pid() + “-” + Thread.currentThread().getId();
.. }
//- read
public static Object globalData(String key){ … }
%>

如此以来,我们拥有了全局的数据容器globalDataHolder, 只是它的读写是线程安全的,但数据并不是线程安全的(没有线程标记),读写带有线程Id标记的数据时,需要通过全局静态方法 globalData .
预期使用场景, 在GWA2 Java的任何代码区域,可以访问到 globalData, 通过这个通道可以轻松读写线程安全的数据。
任意代码区,写数据: globalData(“a-key-name”, Single_Value_Or_List_Object);
读取数据: String aString = (String)globalData(“a-string-key”);

在GWA2 Java的请求处理的 comm/footer 部分,会对全局的数据容器 globalDataHolder与本地的 data数据做进一步的merge操作,然后一同交给下一步的模板处理引擎Hanjst.

这个通道取名 globalData,也参考了GWA2 PHP的做法,比如在PHP中,任意代码块中,可以访问全局变量,使用关键字 global $myObject ,意思是现在要去读取全局变量 $myObject 这个对象了( https://www.php.net/manual/en/language.variables.scope.php )。
GWA2 套系(GWA2 PHP,GWA Perl, GWA2 Python, GWA2 Aspx),跨越多个编程语言,也希望能超越单个语言限制,赋能软件研发,提升生成力。

以上引用的代码块可以在GWA2 的项目GitHub库( https://github.com/wadelau/GWA2 )中查阅,也可以在 gitee上的GWA2( https://gitee.com/xenxin/GWA2 )访问到。

客户问道:更新升级后的 GWA2 Java 还有bug或漏洞吗?
诚惶诚恐地,我们的答案:没有已知的问题了。
哪一个 GWA2 的版本是最好的?
下一个。


全文原发: https://ufqi.com/blog/gwa2-java-multiple-threads-globaldata/ , -R/22SU


GWA2

-GWA2 吉娃兔 是”通用网络应用架构( General Web Application Architeture, https://ufqi.com/dev/gwa2/ )”,基于 -GWA2 可以轻便构建各种网络应用程序,
包括复杂的在线购物商城、在线医疗、在线教育、 旅游交易平台、社群或者社交网站和新闻资讯网站等,
也包括各种企事业单位网上门户,在线交互及服务作业系统等.
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .

-GWA2 is a “General Web Application Architecture” and based on -GWA2 developers can easily build a variety of network applications,
including complex online shopping malls, online medical services, online teaching, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various online portals of enterprises and institutions, online interaction and service operations systems.
Moreover it contains server-side support for Native App, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.

-GWA2 is E.A.S.Y 
Easy Along, Swift Yield
轻松启动, 快速产出.


有福金融UfqiFina : https://ufqi.com/finance

有福金融 是一个旨在促进财富稳步增长的工具平台。
UfqiFina is a platform of tools designed to promote wealth growth steadily.

此条目发表在-GWA2, 编程技术, 计算机技术分类目录,贴了, , , , , , 标签。将固定链接加入收藏夹。

GWA2 Java 增加多线程数据共享通道 globalData》有2条回应

  1. Pingback引用通告: GWA2 Java 增加多线程数据共享通道 globalData | -wordpress-wadelau

  2. Pingback引用通告: GWA2吉娃兔升级增加搜索模糊语法支持 | -wordpress-wadelau

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code