Sesetengah penemuduga suka meminta pelajar menulis semula kunci baharu selepas menerangkan prinsip kunci dan meminta mereka hadir di tempat kejadian . Tulis idea umum dan logik kod pada papan putih soalan temu bual ini secara peribadi saya fikir ia memfokuskan kepada dua bahagian:
Periksa bagaimana pemahaman anda tentang prinsip kunci itu berlaku belum mentafsir kod sumber, anda hanya boleh membaca artikel dalam talian atau menghafal soalan temu duga, dan anda boleh memberitahu prinsip umum, tetapi sukar untuk anda menulis kod pelaksanaan kunci di tempat kejadian, melainkan anda benar-benar membaca kod sumber . Atau mempunyai pengalaman projek yang berkaitan dengan kunci;
Kami tidak perlu mencipta, kami hanya perlu meniru dan menulis semula API sedia ada dalam kunci Java.
Jika anda telah membaca kod sumber, soalan ini sangat mudah anda boleh memilih kunci yang anda biasa tiru.
Secara amnya, apabila menyesuaikan kunci, kami mentakrifkannya berdasarkan keperluan perkara. Senario, sebagai contoh, kunci baca pada sumber yang dikongsi boleh dikongsi, seperti akses dikongsi kepada pautan pangkalan data, contohnya, bilangan pautan pada pelayan Socket boleh dikongsi akses kepada pautan pangkalan data untuk menentukan Kunci.
Anggapkan (andaian berikut adalah semua andaian) bahawa pangkalan data kami adalah mysql yang berdiri sendiri, yang hanya boleh menanggung 10 sambungan apabila membuat pautan pangkalan data JDBC asal Dengan cara ini, kami menggunakan antara muka untuk merangkum proses mencipta pautan menggunakan JDBC Kami menamakan antara muka ini: buat antara muka pautan.
Keperluan keseluruhan untuk pautan pangkalan data akses dikongsi adalah seperti berikut: bilangan pautan mysql untuk semua permintaan digabungkan tidak boleh melebihi 10 (termasuk apabila melebihi 10, ralat akan dilaporkan secara langsung).
Dalam konteks ini, kami mereka bentuk gambar berikut:
Bahagian paling kritikal dalam reka bentuk ini ialah sama ada kita boleh mendapatkan kunci melaluinya sama ada pautan mysql boleh diperoleh, jika kunci boleh diperoleh, maka pautan boleh diperoleh, jika tidak ralat akan dilaporkan terus.
Kemudian mari kita lihat kod yang dilaksanakan:
Mula-mula kita perlu menentukan kunci, yang memerlukan dua elemen:
<.>Takrifan kunci: Penyegerakan penyegerak; kaedah mengunci dan membuka kunci yang disediakan oleh kunci kepada dunia luar. Pelaksanaan kod kunci kongsi adalah seperti berikut:// 共享不公平锁 public class ShareLock implements Serializable{ // 同步器 private final Sync sync; // 用于确保不能超过最大值 private final int maxCount; /** * 初始化时给同步器 sync 赋值 * count 代表可以获得共享锁的最大值 */ public ShareLock(int count) { this.sync = new Sync(count); maxCount = count; } /** * 获得锁 * @return true 表示成功获得锁,false 表示失败 */ public boolean lock(){ return sync.acquireByShared(1); } /** * 释放锁 * @return true 表示成功释放锁,false 表示失败 */ public boolean unLock(){ return sync.releaseShared(1); } }
class Sync extends AbstractQueuedSynchronizer { // 表示最多有 count 个共享锁可以获得 public Sync(int count) { setState(count); } // 获得 i 个锁 public boolean acquireByShared(int i) { // 自旋保证 CAS 一定可以成功 for(;;){ if(i<=0){ return false; } int state = getState(); // 如果没有锁可以获得,直接返回 false if(state <=0 ){ return false; } int expectState = state - i; // 如果要得到的锁不够了,直接返回 false if(expectState < 0 ){ return false; } // CAS 尝试得到锁,CAS 成功获得锁,失败继续 for 循环 if(compareAndSetState(state,expectState)){ return true; } } } // 释放 i 个锁 @Override protected boolean tryReleaseShared(int arg) { for(;;){ if(arg<=0){ return false; } int state = getState(); int expectState = state + arg; // 超过了 int 的最大值,或者 expectState 超过了我们的最大预期 if(expectState < 0 || expectState > maxCount){ log.error("state 超过预期,当前 state is {},计算出的 state is {}",state ,expectState); return false; } if(compareAndSetState(state, expectState)){ return true; } } } }
public class MysqlConnection { private final ShareLock lock; // maxConnectionSize 表示最大链接数 public MysqlConnection(int maxConnectionSize) { lock = new ShareLock(maxConnectionSize); } }
// 得到一个 mysql 链接,底层实现省略 private Connection getConnection(){}
// 对外获取 mysql 链接的接口 // 这里不用try finally 的结构,获得锁实现底层不会有异常 // 即使出现未知异常,也无需释放锁 public Connection getLimitConnection() { if (lock.lock()) { return getConnection(); } return null; } // 对外释放 mysql 链接的接口 public boolean releaseLimitConnection() { return lock.unLock(); }
逻辑也比较简单,加锁时,如果获得了锁,就能返回 Mysql 的链接,释放锁时,在链接关闭成功之后,调用 releaseLimitConnection 方法即可,此方法会把锁的 state 状态加一,表示链接被释放了。
以上步骤,针对 Mysql 链接限制的场景锁就完成了。
锁写好了,接着我们来测试一下,我们写了一个测试的 demo,代码如下:
public static void main(String[] args) { log.info("模仿开始获得 mysql 链接"); MysqlConnection mysqlConnection = new MysqlConnection(10); log.info("初始化 Mysql 链接最大只能获取 10 个"); for(int i =0 ;i<12;i++){ if(null != mysqlConnection.getLimitConnection()){ log.info("获得第{}个数据库链接成功",i+1); }else { log.info("获得第{}个数据库链接失败:数据库连接池已满",i+1); } } log.info("模仿开始释放 mysql 链接"); for(int i =0 ;i<12;i++){ if(mysqlConnection.releaseLimitConnection()){ log.info("释放第{}个数据库链接成功",i+1); }else { log.info("释放第{}个数据库链接失败",i+1); } } log.info("模仿结束"); }
以上代码逻辑如下:
获得 Mysql 链接逻辑:for 循环获取链接,1~10 都可以获得链接,11~12 获取不到链接,因为链接被用完了;释放锁逻辑:for 循环释放链接,1~10 都可以释放成功,11~12 释放失败。
我们看下运行结果,如下图:
从运行的结果,可以看出,我们实现的 ShareLock 锁已经完成了 Mysql 链接共享的场景了。
Atas ialah kandungan terperinci Apakah struktur reka bentuk dan butiran kunci tulis semula Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!