本文介紹3種線程安全模式
1,lock
2,Mutex
3,MethodImpl
以前寫的一個MYSQL數據庫連接池ConnectionPool.CS
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Threading; using MySql.Data.MySqlClient; using System.Runtime.CompilerServices; namespace queue.service.basic { public class ConnectionPool { private Stack<MySqlConnection> pool; private const int POOL_MAX_SIZE = 20; private int current_Size = 0; private string ConnString = "";//連接字符串 private SysProperty sysProperty; private const string SYS_PROPERTY = "config\\SysProperty.xml"; private static ConnectionPool connPool; private ConnectionPool() { if (pool == null) { pool = new Stack<MySqlConnection>(); } } [MethodImpl(MethodImplOptions.Synchronized)] public static ConnectionPool getInstance() { if (connPool == null) { connPool = new ConnectionPool(); } return connPool; } public MySqlConnection getConnection() { MySqlConnection conn; lock (this) { if (pool.Count == 0) { if (current_Size < POOL_MAX_SIZE) { conn = createConnection(); current_Size++; //把conn加入到pool 中 pool.Push(conn); } else { try { Monitor.Wait(this); } catch (Exception e) { Console.WriteLine(e.Message); } } } conn = (MySqlConnection)pool.Pop(); } return conn; } private string GetConnString() { if (ConnString == "") { sysProperty = new SysProperty().LoadProperty(Path.Combine(SYS_PROPERTY)); string ip = sysProperty.getPropertyValue("databaseIP"); string dbName = sysProperty.getPropertyValue("databaseName"); string userID = sysProperty.getPropertyValue("databaseUser"); string userPwd = sysProperty.getPropertyValue("databasePassword"); ConnString = "Database=" + dbName + ";Data Source=" + ip + ";User Id=" + userID + ";Password=" + userPwd + ";" + "pooling=true;CharSet=utf8;port=3306;"; } return ConnString; } public void releaseConnection(MySqlConnection conn) { lock (this) { pool.Push(conn); Monitor.Pulse(this); } } private MySqlConnection createConnection() { lock (this) { MySqlConnection newConn = new MySqlConnection(GetConnString()); newConn.Open(); return newConn; } } } }
總結:
1,上面類中使用了 主要使用了 lock 方式。
lock()是對一個對象加互斥鎖,只允許一個線程訪問其后大括號中語句塊,直到該語句塊的代碼執行完才解鎖,解鎖后才允許其他的線程執行其語句塊。
2,單例模式使用了懶漢模式。
餓漢式是在類裝載的時候直接得到該類的實例,可以說是前期綁定的;懶漢式是后期綁定的,類加載的時候connPool是空的,在需要的時候才被創建且僅創建一次。餓漢式的速度快,效率高,但是耗費系統資源;懶漢式則相反。懶漢式還存在一個問題,就是后期綁定不能確保對象只能被實例化一次,這需要對指示類是否實例化的標志設置1個互斥鎖,僅允許1個線程訪問。這樣就可以確保對象只被實例化一次。
3,單例模式的線程安全使用了 MethodImpl。
他指定了getInstance()方法同時只能被一個線程使用。
4,使用Mutex類進行同步
修改代碼為:
private static Mutex mutex = new Mutex(); public static ConnectionPool getInstance() { mutex.WaitOne(); if (connPool == null) { connPool = new ConnectionPool(); } mutex.ReleaseMutex(); return connPool; }