Programmēšana

Izveidojiet pats savu ObjectPool Java, 1. daļa

Objektu apvienošanas ideja ir līdzīga vietējās bibliotēkas darbībai: Kad vēlaties lasīt grāmatu, jūs zināt, ka lētāk ir aizņemties kopiju no bibliotēkas, nevis iegādāties savu eksemplāru. Tāpat procesam ir lētāk (attiecībā uz atmiņu un ātrumu) aizņemties objektu, nevis izveidot savu kopiju. Citiem vārdiem sakot, bibliotēkas grāmatas attēlo objektus, bet bibliotēkas patrons - procesus. Kad procesam ir nepieciešams objekts, tas pārbauda objektu kopijas kopiju, nevis izveido jaunu. Pēc tam process atgriež objektu pūlā, kad tas vairs nav vajadzīgs.

Tomēr ir dažas nelielas atšķirības starp objektu apvienošanu un bibliotēkas analoģiju, kas būtu jāsaprot. Ja bibliotēkas patrons vēlas konkrētu grāmatu, bet tiek pārbaudīti visi šīs grāmatas eksemplāri, patronam jāgaida, līdz kopija tiek atgriezta. Mēs nekad nevēlamies, lai procesam būtu jāgaida objekts, tāpēc objektu kopa nepieciešamības gadījumā veiks jaunas kopijas. Tas varētu novest pie tā, ka baseinā gulēs pārmērīgi daudz objektu, tāpēc tas arī saskaitīs neizmantotos priekšmetus un periodiski tos iztīrīs.

Mans objektu kopas dizains ir pietiekami vispārīgs, lai apstrādātu uzglabāšanas, izsekošanas un derīguma termiņus, taču noteiktu objektu tipu eksponēšana, validēšana un iznīcināšana ir jāveic apakšklasē.

Tagad, kad pamati ir novirzīti, ļaujiet pāriet uz kodu. Šis ir skeleta objekts:

 publiskā abstraktā klase ObjectPool {private long expirationTime; privāta Hashtable bloķēta, atbloķēta; abstrakts Objekta izveide (); abstrakts Būla vērtības apstiprinājums (objekts o); abstraktā tukšuma termiņš beidzas (objekts o); sinhronizēta objekta pārbaude () {...} sinhronizēta tukšuma pārbaude (objekts o) {...}} 

Apkopoto objektu iekšējā glabāšana tiks veikta ar diviem Hashtable objekti, viens bloķētiem objektiem un otrs atbloķētiem. Paši objekti būs hashtable atslēgas, un to pēdējā izmantošanas laiks (laikmeta milisekundēs) būs vērtība. Uzglabājot objekta pēdējo izmantošanas reižu, baseins tam var beigties un atbrīvot atmiņu pēc noteikta neaktivitātes laika.

Galu galā objektu kopa ļautu apakšklasē norādīt hashtable sākotnējo lielumu, kā arī to augšanas ātrumu un derīguma termiņu, taču es cenšos to padarīt vienkāršu šī raksta vajadzībām, stingri kodējot šīs vērtības konstruktors.

 ObjectPool () {expirationTime = 30000; // 30 sekundes bloķētas = new Hashtable (); atbloķēts = jauns Hashtable (); } 

The checkOut () metode vispirms pārbauda, ​​vai atbloķētajā hashtable ir kādi objekti. Ja tā, tas tos apritē un meklē derīgu. Apstiprināšana ir atkarīga no divām lietām. Pirmkārt, objektu kopa pārbauda, ​​vai objekta pēdējais izmantošanas laiks nepārsniedz apakšklasē norādīto derīguma termiņu. Otrkārt, objektu kopa izsauc abstraktu apstiprināt () metode, kas veic jebkuru klases pārbaudi vai atkārtotu inicializāciju, kas nepieciešama objekta atkārtotai izmantošanai. Ja objekta pārbaude neizdodas, tas tiek atbrīvots un cilpa turpina virzīties uz nākamo objektu hashtable. Kad tiek atrasts objekts, kas iztur validāciju, tas tiek pārvietots uz bloķēto hashtable un tiek atgriezts pie procesa, kas to pieprasīja. Ja atbloķētā hashtable ir tukša vai neviens no tā objektiem neiztur validāciju, tiek izveidots jauns objekts un tas tiek atgriezts.

 sinhronizēts Object checkOut () {long now = System.currentTimeMillis (); Objekts o; ja (unlocked.size ()> 0) {Uzskaitījums e = unlocked.keys (); while (e.hasMoreElements ()) {o = e.nextElement (); ja ((tagad - ((Long) unlocked.get (o)) .longValue ())> expirationTime) {// objekts ir beidzies unlocked.remove (o); derīguma termiņš (o); o = nulle; } else {if (validate (o)) {unlocked.remove (o); locked.put (o, jauns Long (tagad)); atgriešanās (o); } else {// objekta pārbaude neizdevās, unlocked.remove (o); derīguma termiņš (o); o = nulle; }}}} // nav pieejamu objektu, izveidojiet jaunu o = create (); locked.put (o, jauns Long (tagad)); atgriešanās (o); } 

Tā ir vissarežģītākā metode ObjectPool klase, tas viss ir lejup no šejienes. The reģistrēties() metode vienkārši pārvieto ievadīto objektu no bloķētās hashtable uz atbloķēto hashtable.

sinhronizēta void checkIn (Object o) {locked.remove (o); unlocked.put (o, jauns Long (System.currentTimeMillis ())); } 

Trīs atlikušās metodes ir abstraktas, tāpēc tās jāievieš apakšklasē. Šī raksta labad es izveidošu datu bāzes savienojumu kopu, ko sauc JDBCConnectionPool. Lūk, skelets:

 publiskā klase JDBCConnectionPool paplašina ObjectPool {privātā virkne dsn, usr, pwd; public JDBCConnectionPool () {...} create () {...} validate () {...} expire () {...} public Connection borrowConnection () {...} public void returnConnection () {. ..}} 

The JDBCConnectionPool lietojumprogrammai būs jāprecizē datubāzes draiveris, DSN, lietotājvārds un parole pēc saīsināšanas (izmantojot konstruktoru). (Ja jums tas viss ir grieķu valoda, neuztraucieties, JDBC ir cita tēma. Vienkārši izturieties ar mani, līdz mēs atgriezīsimies pie apvienošanās.)

 public JDBCConnectionPool (String draiveris, String dsn, String usr, String pwd) {mēģiniet {Class.forName (draiveris) .newInstance (); } catch (izņēmums e) {e.printStackTrace (); } tas.dsn = dsn; this.usr = usr; this.pwd = pwd; } 

Tagad mēs varam ienirt abstrakto metožu ieviešanā. Kā jūs redzējāt checkOut () metode, ObjectPool izsauks izveidot () no savas apakšklases, kad tai būs jāpiedāvā jauns objekts. Priekš JDBCConnectionPool, mums atliek tikai izveidot jaunu Savienojums objektu un nodot to atpakaļ. Atkal, lai saglabātu šo rakstu vienkāršu, es metu piesardzību pret vēju un ignorēju visus izņēmumus un nulles rādītāja nosacījumus.

 Objekta izveide () {try {return (DriverManager.getConnection (dsn, usr, pwd)); } catch (SQLException e) {e.printStackTrace (); atgriešanās (null); }} 

Pirms ObjectPool atbrīvo objektu, kuram beidzies derīguma termiņš (vai nederīgs) atkritumu savākšanai, tas nodod to savai apakšklasei derīguma termiņš () metode jebkuras nepieciešamās attīrīšanas veikšanai pēdējā brīdī (ļoti līdzīga pabeigt () metodi, kuru izsaucis atkritumu savācējs). Gadījumā, ja JDBCConnectionPool, viss, kas mums jādara, ir jānoslēdz savienojums.

void expire (Object o) {try {((Connection) o) .close (); } catch (SQLException e) {e.printStackTrace (); }} 

Visbeidzot, mums ir jāievieš validācijas () metode ObjectPool zvani, lai pārliecinātos, ka objekts joprojām ir derīgs lietošanai. Šī ir arī vieta, kur jāveic jebkura atkārtota inicializācija. Priekš JDBCConnectionPool, mēs vienkārši pārbaudām, vai savienojums joprojām ir atvērts.

 boolean validate (Object o) {try {return (! ((Savienojums) o) .isClosed ()); } catch (SQLException e) {e.printStackTrace (); atgriešanās (nepatiesa); }} 

Tas viss iekšējai funkcionalitātei. JDBCConnectionPool ļaus lietojumprogrammai aizņemties un atgriezt datubāzes savienojumus, izmantojot šīs neticami vienkāršās un pareizi nosauktās metodes.

 public Connection borrowConnection () {return ((Connection) super.checkOut ()); } public void returnConnection (Savienojums c) {super.checkIn (c); } 

Šim dizainam ir pāris trūkumi. Varbūt vislielākā ir iespēja izveidot lielu objektu kopumu, kas nekad netiek atbrīvots. Piemēram, ja virkne procesu vienlaikus pieprasa objektu no pūla, baseins izveidos visus nepieciešamos gadījumus. Tad, ja visi procesi objektus atgriež atpakaļ baseinā, bet checkOut () nekad vairs netiek izsaukts, neviens objekts netiek iztīrīts. Tas ir reti sastopams aktīvām lietojumprogrammām, taču daži back-end procesi, kuriem ir dīkstāves laiks, var radīt šo scenāriju. Es atrisināju šo dizaina problēmu ar "tīrīšanas" pavedienu, taču šo diskusiju es saglabāju šī raksta otrajā pusē. Es pievērsīšos arī pareizai kļūdu apstrādei un izņēmumu izplatīšanai, lai kopu padarītu stabilāku misijai kritiskām lietojumprogrammām.

Tomass E. Deiviss ir Sun sertificēts Java programmētājs. Pašlaik viņš dzīvo saulainajā Floridas dienvidos, taču cieš kā darbaholiķis un lielāko daļu laika pavada telpās.

Šo stāstu "Izveidojiet savu ObjectPool Java, 1. daļa" sākotnēji publicēja JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found