项目需求:
产品需要监视不同种类的多个数据库,例如:多个mysql库,多个oracle库,多个sybase库,多个msserver库等等,连接池需要根据客户数据库种类和数量的实际情况进行动态创建。
难点:
1.每个库创建一个连接池,不能重复创建。
2.每个连接池维护自身的线程安全性,访问每个连接池的线程单独排队,相互之间不能影响。
实现思路:
将每个库的连接池实例保存到一个static Map中,key为库路径,value为连接池对象。如果对象已经存在,则不再创建,直接获取。
Map的read-write的组合操作,需要线程安全控制。创建连接池对象时,需要先初始化pool对象,这是一个耗时的操作,这时引申出一个问题,以什么作为锁来较好地控制对Map的操作?
如果是全局变量锁,则会导致不同的数据库都会在这里阻塞,如果一台数据库宕掉,其他数据库也会大量阻塞。如果用库地址作为独占锁,则可以实现不同的数据库各自排队,库和库之间没有影响。因为库路径是String对象,为此也专门测试了一下Java String对象是否可以做锁变量。结论是Java String对象不能作为Synchronized()的锁变量。但是Object对象可以作为锁,很奇怪!
不能在全局变量上加锁的主要原因是初始化连接池对象时间较长,线程排队会比较严重,而且多数据库间互相影响。所以考虑添加一个锁集合,以数据库路径为key,以Object对象为value,这样可以较快的获取Object对象,并且可以用这个对象代替key(数据库路径)作为synchrozied的锁变量。上代码:
import java.sql.Connection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.mchange.v2.c3p0.ComboPooledDataSource; public class XJDBCPool { public static enum DBTYPE { Oracle, Sybase, Mysql, Mssql, DB2, Informix }; //locks map public final static Map<String, Object> locks = new ConcurrentHashMap<String, Object>(); //pool map public final static Map<String, C3p0Pool> jdbcPoolC3p0s = new ConcurrentHashMap<String, C3p0Pool>(); private static XConnection getXCon(String key, String type) { Logger.logDebug("~~~~ XJDBCPool getXCon key : "+ key); int timeoutIndex = key.lastIndexOf("#"); String timeStr = key.substring(timeoutIndex + 1) == null ? "" : key.substring(timeoutIndex + 1); int timeout = Integer.valueOf(timeStr); key = key.substring(0, timeoutIndex); C3p0Pool c3p0Pool = null; if(type.equals(JDBC_TYPE_C3P0)){ Object obj = null; synchronized(locks){ obj = locks.get(key); if(obj == null){ obj = new Object(); locks.put(key, obj); } } Logger.logDebug("~~~~ ["+ Thread.currentThread().getName() +"] wait lock : "+ obj +" key : "+ key); synchronized(obj){ Logger.logDebug("~~~~ ["+ Thread.currentThread().getName() +"] get lock : "+ obj +" key : "+ key); c3p0Pool = jdbcPoolC3p0s.get(key); if (c3p0Pool == null){ //init pool c3p0Pool = new C3p0Pool(key, timeout); jdbcPoolC3p0s.put(key, c3p0Pool); } else{ //if timeout was modified, restart pool. int timeoutOld = 0; ComboPooledDataSource cpds = c3p0Pool.getCpds(); if(cpds != null){ timeoutOld = cpds.getCheckoutTimeout(); if(timeout * 1000 != timeoutOld){ c3p0Pool.release(); cpds = c3p0Pool.init(key, timeout); jdbcPoolC3p0s.put(key, c3p0Pool); } } } } Logger.logDebug("~~~~ ["+ Thread.currentThread().getName() +"] release lock : "+ obj +" key : "+ key); } return c3p0Pool.getConnection(); } .... }
“String对象不能作为synchrozied的锁变量”
测试程序如下,控制台输出大家相信都能看得懂,就不再做解释。
import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; public class TestSynchronizedStr { public static Logger logger = Logger.getLogger(LoggerManager.PLATFORM); public final static Map<String, Object> locks = new ConcurrentHashMap<String, Object>(); private final static Map<String, Object> jdbcPoolC3p0s = new ConcurrentHashMap<String, Object>(); /** * test ConcurrentHashMap */ public static void testConcurrentMap(String key){ Object obj = null; synchronized(locks){ obj = locks.get(key); if(obj == null){ obj = new Object(); locks.put(key, obj); } } logger.debug("~~~~ ["+ Thread.currentThread().getName() +"] wait lock : "+ key); synchronized(obj){ logger.debug("~~~~ ["+ Thread.currentThread().getName() +"] get lock : "+ key); try{ Thread.sleep(10000L); } catch(Exception e){ e.printStackTrace(); } logger.debug("~~~~ ["+ Thread.currentThread().getName() +"] release lock : "+ key); } } public static void startThreads(final String i) { Thread[] threads = new Thread[10]; for(int j = 0; j < threads.length; j++){ threads[j] = new Thread(){ public void run(){ logger.debug("\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); logger.debug("**** start ["+ Thread.currentThread().getName() +"]"); testConcurrentMap(i); } }; threads[j].start(); } } public static void main(String[] args) { for (int i = 0; i < 50; i++) { Random random = new Random(); int randNum = Math.abs(random.nextInt())%3; startThreads(randNum +""); } } }
相关推荐
我们在使用 synchronized 关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。 synchronized 方法被修饰的方法称为同步方法,其...
synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。...
- 尽量减小同步的范围,即缩小`synchronized`代码块。过度使用`synchronized`方法可能导致不必要的阻塞,降低性能。优先考虑使用`synchronized`块,只锁定必要的代码部分。如果必须使用方法级别同步,考虑使用`Lock...
Java 6通过改进内部锁的管理算法,使得内置锁的性能有了显著提升,这在一定程度上缩小了与ReentrantLock之间的性能差异。 读-写锁(ReadWriteLock)是另一种显示锁机制,适用于读操作远多于写操作的场景。读-写锁...
Java中,内存模型规定了线程间如何共享和访问变量,而同步机制如`synchronized`关键字就是用来保证内存可见性和原子性。但是,过度使用同步可能导致更多的内存同步开销。 再者,线程阻塞是指一个线程因为无法获取锁...
- **Lock接口与ReentrantLock**:提供了比synchronized更细粒度的锁控制,支持公平锁和非公平锁。 - **java.util.concurrent.atomic包**:提供原子操作类,如AtomicInteger、AtomicLong等,用于无锁编程。 3. **...
Java Lock与Condition是Java并发编程中的重要概念,它们提供了比synchronized关键字更细粒度的控制,从而使得多线程程序的设计和管理更加灵活高效。本文将深入探讨ReentrantLock(可重入锁)和Condition的基本原理、...
使用synchronized关键字时,尽量缩小锁的粒度,考虑使用Lock接口提供的高级同步机制,如ReentrantLock。另外,合理利用并发容器,如ConcurrentHashMap,它们内部设计有优化的并发控制,比简单的同步集合更高效。 除...
尽量缩小锁的粒度,使用`Lock`接口(如`ReentrantLock`)提供更细粒度的控制。如果可能,使用并发集合类(如`ConcurrentHashMap`)代替同步的`HashMap`。 5. **使用并发编程策略**:Java的并发库提供了很多高效工具...
同步方法通过`synchronized`关键字实现,确保同一时间只有一个线程能够执行特定的方法或代码块,从而避免数据不一致性和竞态条件。然而,过度或不当使用同步方法可能导致性能问题,尤其是当多个线程频繁争用同一锁时...
瘦锁技术在Java虚拟机(JVM)中实现的基础是细粒度锁(Fine-Grained Locking),它允许对共享资源进行更精确的锁定。通过缩小锁的范围,即只锁定真正需要同步的代码块,可以减少不必要的锁争用和等待时间。这种技术...
6. **并发处理**:提倡使用并发容器如`ConcurrentHashMap`替代普通`HashMap`在多线程环境下的使用,避免使用`synchronized`修饰整个方法,而应尽量缩小锁的粒度,使用`synchronized`块或`Lock`。 7. **控制语句**:...
7. **谨慎使用synchronized**:同步可能导致性能下降和死锁风险,只在必要时使用,并尽量缩小同步范围。理解同步的粒度,方法同步和代码块同步的差异。 8. **字符串连接首选StringBuilder或StringBuffer**:在进行...
另外,`java.util.concurrent`包提供了许多并发数据结构和工具类,如`ReentrantLock`、`Semaphore`等,它们允许更细粒度的控制和优化。 另一种优化策略是使用分别锁(也称为分段锁),将大型数据结构分割成小块,每...
13.4 在synchronized和ReentrantLock之间进行选择234 13.5 读-写锁235 第14章 构建自定义的同步工具238 14.1 状态依赖性的管理238 14.1.1 示例:将前提条件的失败传递给调用者240 14.1.2 示例:通过轮询与休眠...
例如,将同步块尽可能缩小,仅在必要的代码段使用同步关键字,避免无谓的等待。 ```java // 优化前 public synchronized void syncMethod() { othercode1(); mutextMethod(); othercode2(); } // 优化后 public...
17. **细粒度同步**:通过缩小`synchronized`块的范围,减少锁的竞争,提高效率。 18. **线程间的通信**:可以使用wait/notify机制,wait()需配合notify()或notifyAll()使用,wait(毫秒数)可以在指定时间后结束等待...
- **锁的对象**:同步方法默认使用当前对象作为锁,而同步代码块可以指定任意对象为锁,这允许更细粒度的控制,可以避免因一个线程阻塞而导致其他不相关的线程也被阻塞的情况。 - **可读性**:同步方法的语法简洁,...