共享连接¶
线程安全简介¶
线程是存在于较大进程中的轻量级进程。每个线程共享相同的代码和数据段,但有自己的程序计数器、系统寄存器和堆栈。全局变量和静态变量对所有线程都是通用的,可能需要一种互斥机制来管理应用程序中多个线程对这些变量的访问。
一旦产生线程,线程之间就会异步运行。它们可以访问公共数据元素并以任意顺序进行ACCI调用。由于对数据元素的这种共享访问,需要一种机制来维护多个线程访问的数据的完整性。管理数据访问的机制采用互斥锁(mutual exclusivity locks)的形式,它确保访问应用程序内共享资源的多个线程之间不会发生冲突。在ACCI中,互斥锁是基于ACCI环境授予的。
神通数据库服务器和ACCI库的线程安全特性使开发人员能够在多线程应用程序中使用ACCI,并带来以下好处:
- 多个执行线程可以调用ACCI,其结果与单个线程连续调用的结果相同。
- 当多个线程进行ACCI调用时,线程之间不会产生副作用。
- 即使您没有编写多线程程序,也不会因为包含线程安全的ACCI调用而付出任何性能损失。
- 使用多线程可以提高程序的性能。在多处理器系统中,线程在单独的处理器上并发运行,而在单处理器系统中,较慢的操作和较快的操作之间可能出现重叠。
除了客户机/服务器应用程序(客户机可以是多线程程序)之外,线程安全通常用于三层架构或客户机/代理/服务器架构。在此体系结构中,客户机只关心表示服务。代理(或应用程序服务器)为客户端应用程序处理应用程序逻辑。通常,这种关系是多对一关系,多个客户机共享相同的应用服务器。
三层架构中的服务器层是神通数据库服务器。应用程序服务器(代理)支持多线程,每个线程服务于一个独立的客户机应用程序。在Oracle环境中,中间层应用服务器是ACCI或预编译器程序。
实现线程安全¶
要通过使用ACCI来利用线程安全性,应用程序必须运行在线程安全的操作系统中。然后,应用程序必须为createEnvironment()方法的模式参数指定THREADED_MUTEXED或THREADED_UNMUTEXED,从而通知ACCI应用程序正在以多线程模式运行。例如,打开互斥锁,发出下面的声明:
Environment *env = Environment::createEnvironment(Environment::THREADED_MUTEXED);
注意,一旦使用THREADED_MUTEXED或THREADED_UNMUTEXED调用createEnvironment方法,所有后续对createEnvironment方法的调用也必须使用THREADED_MUTEXED或THREADED_UNMUTEXED模式进行。
如果一个多线程应用程序在一个线程安全的操作系统中运行,那么ACCI库在每个ACCI环境的基础上管理应用程序的互斥对象。但是,您可以覆盖这个特性,并让应用程序维护自己的互斥锁方案。这是通过将模式值THREADED_UNMUTEXED指定给createEnvironment()方法来实现的。
运行在非线程安全平台上的应用程序不应该将THREADED_MUTEXED或THREADED_UNMUTEXED的值传递给createEnvironment()方法。
如果应用程序是单线程的,无论平台是否线程安全,应用程序都应该将Environment::DEFAULT值传递给createEnvironment()方法。这也是mode参数的默认值。以THREADED_MUTEXED模式运行的单线程应用程序可能会导致性能下降。
ACCI不支持非阻塞模式。
序列化¶
作为一个应用程序程序员,对于多线程应用程序的并发性,你有两个基本的选择:
自动序列化¶
在有多个线程操作来自ACCI环境的对象(连接和连接池)的情况下,您可以选择让ACCI序列化对这些对象的访问。第一步是将THREADED_MUTEXED的值传递给createEnvironment方法。此时,ACCI库在环境中的线程安全对象上自动获得互斥锁。
当使用THREADED_MUTEXED模式创建ACCI环境时,只有Environment、Map、ConnectionPool和Connection对象是线程安全的。也就是说,如果两个线程同时调用其中一个对象,ACCI将在内部序列化它们。但是,请注意,所有其他ACCI对象,如Statement、ResultSet、SQLException、Stream等等,都不是线程安全的,因为应用程序不应该从多个线程同时操作这些对象。
请注意,ACCI调用的大量处理发生在服务器上,因此如果两个ACCI调用的线程去使用同一个连接,那么其中一个线程可能被阻塞,而另一个线程则在服务器上完成处理。
应用程序提供的序列化¶
在有多个线程操作来自ACCI环境的对象的情况下,您可以选择管理序列化。第一步是为createEnvironment模式传递一个THREADED_UNMUTEXED值。在这种情况下,应用程序必须对来自相同ACCI环境的对象进行相互独占锁定ACCI调用。这样做的好处是,互斥锁方案可以根据应用程序设计进行优化,以获得更大的并发性。
当以这种模式创建ACCI环境时,ACCI会识别出应用程序是在多线程应用程序中运行的,但ACCI不需要获得它的内部互斥锁。ACCI假定对源自该ACCI环境的对象方法的所有调用都由应用程序序列化。你可以用两种不同的方式实现这一点:
- 每个线程都有自己的环境。也就是说,环境和从它派生的所有对象(连接、连接池、语句、结果集等等)不能跨线程共享。在这种情况下,您的应用程序不需要应用任何互斥对象。
- 如果应用程序跨线程共享ACCI环境或从该环境派生的任何对象,那么它必须序列化对这些对象的访问(通过使用互斥锁等等),以便只有一个线程在这些对象上调用ACCI方法。
在这两种情况下,ACCI都不会获取互斥对象。您必须确保在进程中使用THREADED_UNMUTEXED时,在任何给定时间,从ACCI环境派生的任何对象上只有一个ACCI调用。
ACCI经过优化,可以尽可能多地重用对象。由于每个环境都有自己的堆,多个环境会导致内存消耗的增加。拥有多个环境可能意味着需要重复有关连接、连接池、语句和结果集对象的工作。这将导致内存的进一步消耗。
到服务器的多个连接会导致服务器和网络上更多的资源消耗。拥有多个环境通常需要更多的连接。