Programavimas

Telkti išteklius naudodami „Apache's Commons Pool Framework“

Išteklių telkimas (dar vadinamas objektų kaupimu) tarp kelių klientų yra metodas, naudojamas skatinti objektų pakartotinį naudojimą ir sumažinti naujų išteklių kūrimo pridėtines išlaidas, o tai lemia geresnį našumą ir pralaidumą. Įsivaizduokite sunkią „Java“ serverio programą, kuri siunčia šimtus SQL užklausų, atidarydama ir uždarydama ryšius kiekvienai SQL užklausai. Arba žiniatinklio serveris, aptarnaujantis šimtus HTTP užklausų, tvarkantis kiekvieną užklausą sukuriant atskirą giją. Arba įsivaizduokite, kaip kiekvienai užklausai išanalizuoti dokumentą sukurti XML analizatoriaus egzempliorių nenaudojant egzempliorių. Tai yra keli scenarijai, dėl kurių reikia optimizuoti naudojamus išteklius.

Išteklių naudojimas kartais gali pasirodyti kritinis sunkiųjų programų atveju. Kai kurios garsios interneto svetainės buvo uždarytos, nes nesugebėjo atlaikyti didelių krovinių. Daugumą problemų, susijusių su sunkiais kroviniais, galima išspręsti makrolygiu, naudojant grupavimo ir apkrovos balansavimo galimybes. Programos lygmeniu išlieka susirūpinimas dėl pernelyg didelio objektų kūrimo ir ribotų serverio išteklių, tokių kaip atmintis, procesorius, gijos ir duomenų bazių jungtys, prieinamumo, o tai gali būti potencialūs trūkumai ir, jei jie nebus naudojami optimaliai, sugadins visą serverį.

Kai kuriais atvejais duomenų bazės naudojimo politika gali priversti apriboti vienu metu esančių ryšių skaičių. Be to, išorinė programa gali padiktuoti ar apriboti tuo pačiu metu atidarytų ryšių skaičių. Tipiškas pavyzdys yra domeno registras (pvz., „Verisign“), ribojantis registratorių (pvz., „BulkRegister“) galimų aktyvių lizdų jungčių skaičių. Išteklių telkimas pasirodė esąs vienas geriausių būdų sprendžiant tokio tipo problemas ir tam tikru mastu taip pat padeda palaikyti reikiamą įmonės programų paslaugų lygį.

Dauguma „J2EE“ programų serverių tiekėjų teikia išteklių kaupimą kaip neatsiejamą jų žiniatinklio ir EJB („Enterprise JavaBean“) talpyklų dalį. Norėdami prisijungti prie duomenų bazės, serverio pardavėjas paprastai pateikia Duomenų šaltinis sąsaja, kuri veikia kartu su JDBC („Java Database Connectivity“) tvarkyklių pardavėju „ConnectionPoolDataSource“ įgyvendinimas. „ConnectionPoolDataSource“ diegimas tarnauja kaip išteklių valdytojo sujungimo gamykla, sujungta java.sql. Ryšys objektai. Panašiai, EJB pupelių be pilietybės, pranešimais pagrįstų pupelių ir subjekto pupelių egzemplioriai sujungiami į EJB konteinerius, kad būtų didesnis našumas ir našumas. XML analizatoriaus egzemplioriai taip pat yra kandidatai į sujungimą, nes kuriant analizatoriaus egzempliorius sunaudojama daug sistemos išteklių.

Sėkmingas atvirojo šaltinio išteklių telkimo diegimas yra „Commons Pool Framework“ DBCP - duomenų bazės jungčių kaupimo komponentas iš „Apace Software Foundation“, plačiai naudojamas gamybinės klasės įmonių programose. Šiame straipsnyje aš trumpai aptariu „Commons Pool“ sistemos vidinius elementus ir naudoju juos diegiant „thread pool“.

Pirmiausia pažiūrėkime, ką suteikia sistema.

„Commons Pool“ sistema

„Commons Pool“ sistema siūlo pagrindinį ir patikimą savavališkų objektų sujungimo įgyvendinimą. Pateikiami keli diegimai, tačiau šio straipsnio tikslams naudojame bendriausią diegimą „GenericObjectPool“. Jis naudoja a „CursorableLinkedList“, kuris yra dvigubai susietas sąrašas („Jakarta Commons“ kolekcijos dalis), kaip pagrindinė sujungtų objektų laikymo duomenų struktūra.

Be to, sistema pateikia sąsajų rinkinį, kuriame pateikiami gyvavimo ciklo metodai ir pagalbiniai metodai, skirti valdyti, stebėti ir išplėsti telkinį.

Sąsaja org.apache.commons.PoolableObjectFactory apibrėžia šiuos gyvavimo ciklo metodus, kurie yra būtini įgyvendinant sutelkimo komponentą:

 // Sukuria egzempliorių, kurį gali grąžinti telkinio viešasis objektas makeObject () {} // Sunaikina egzempliorių, kurio baseinui nebereikia, viešasis void destrObject (Object obj) {} // Patvirtinkite objektą prieš naudodami jį viešasis loginis „validateObject“ (Object obj) {} // Inicializuokite egzempliorių, kurį grąžins baseinas public void activObject (Object obj) {} // Neinicializuokite egzempliorių, kuris bus grąžintas baseinui public void passivateObject (Object obj) {}

Kaip galite padaryti naudodamiesi parašų parašais, ši sąsaja pirmiausia susijusi su:

  • „makeObject“ (): Įgyvendinkite objekto kūrimą
  • sunaikinti objektą (): Įgyvendinkite objekto sunaikinimą
  • validateObject (): Patikrinkite objektą prieš jį naudodami
  • activObject (): Įdiegti objekto inicijavimo kodą
  • passivateObject (): Įdiegti objekto inicializavimo kodą

Kita pagrindinė sąsaja -org.apache.commons.ObjectPool- apibrėžia šiuos grupės valdymo ir stebėjimo metodus:

 // Gaukite egzempliorių iš mano telkinio Object borrowObject () meta Exception; // Grąžinkite egzempliorių mano telkiniui void returnObject (Object obj) meta Exception; // Panaikina objektą iš telkinio void invalidateObject (Object obj) throws Exception; // Naudojamas išankstiniam baseino su nenaudojamais objektais įkėlimui void addObject () throws Exception; // Grąžinkite nenaudojamų egzempliorių skaičių int getNumIdle () meta „UnsupportedOperationException“; // Pateikti aktyvių egzempliorių skaičių int getNumActive () meta „UnsupportedOperationException“; // Išvalo tuščiosios eigos objektus void clear () meta Exception, UnsupportedOperationException; // Uždaryti baseiną void close () throws Exception; // Nustatykite objektą ObjectFactory, naudojamą egzemplioriams kurti. Void setFactory („PoolableObjectFactory factory“) meta „IllegalStateException“, „UnsupportedOperationException“;

„ObjectPool“ sąsajos diegimas trunka a „PoolableObjectFactory“ kaip argumentas jo konstruktoriuose, tokiu būdu objekto kūrimą deleguodamas į savo poklasius. Čia mažai kalbu apie dizaino modelius, nes tai nėra mūsų dėmesys. Skaitytojams, norintiems pažvelgti į UML klasės diagramas, skaitykite šaltinius.

Kaip minėta aukščiau, klasė org.apache.commons.GenericObjectPool yra tik vienas programos įgyvendinimas org.apache.commons.ObjectPool sąsaja. Sistema taip pat teikia raktinių objektų telkinių diegimą, naudojant sąsajas org.apache.commons.KeyedObjectPoolFactory ir org.apache.commons.KeyedObjectPool, kur galima susieti baseiną su raktu (kaip HashMap) ir taip valdyti kelis fondus.

Raktas į sėkmingą telkimo strategiją priklauso nuo to, kaip sukonfigūruosime telkinį. Blogai sukonfigūruoti telkiniai gali būti išteklių šernai, jei konfigūracijos parametrai nėra tinkamai sureguliuoti. Pažvelkime į keletą svarbių parametrų ir jų paskirtį.

Konfigūracijos informacija

Baseiną galima sukonfigūruoti naudojant GenericObjectPool.Config klasė, kuri yra statinė vidinė klasė. Arba mes galime tiesiog naudoti „GenericObjectPool“nustatymo metodai vertėms nustatyti.

Šiame sąraše išsamiai aprašomi kai kurie galimi. Konfigūravimo parametrai „GenericObjectPool“ įgyvendinimas:

  • maxIdle: Maksimalus miegančių atvejų skaičius baseine, neišleidžiant papildomų daiktų.
  • min. tuščiąja eiga: Mažiausias miegančių atvejų skaičius baseine, nesukuriant papildomų objektų.
  • maxActive: Didžiausias aktyvių egzempliorių skaičius telkinyje.
  • timeBetweenEvictionRunsMillis: Milisekundžių miego skaičius tarp tuščiosios eigos objekto iškraustymo gijos eigos. Kai neigiamas, neveikia tuščiosios eigos objektų iškeldinimo gija. Šį parametrą naudokite tik tada, kai norite paleisti iškeldinimo siūlą.
  • minEvictableIdleTimeMillis: Mažiausias laikas, kai objektas, jei jis yra aktyvus, gali sėdėti nenaudojamas baseine, kol jį bus galima iškraustyti nuo tuščiosios eigos objekto iškeldintojo. Jei pateikiama neigiama vertė, vien dėl tuščiosios eigos laiko objektai nėra iškeldinami.
  • testOnBorrow: Kai „tiesa“, objektai patvirtinami. Jei nepavyksta patvirtinti objekto, jis bus išmestas iš baseino ir baseinas bandys skolintis kitą.

Norint pasiekti maksimalų našumą ir pralaidumą, aukščiau nurodytiems parametrams turėtų būti pateiktos optimalios vertės. Kadangi naudojimo būdas kiekvienoje programoje skiriasi, sureguliuokite grupę skirtingais parametrų deriniais, kad pasiektumėte optimalų sprendimą.

Norėdami daugiau sužinoti apie telkinį ir jo vidų, įgyvendinkime gijų telkinį.

Siūlomi siūlų baseino reikalavimai

Tarkime, mums buvo liepta suprojektuoti ir įdiegti darbo planavimo programos gijų telkinio komponentą, kuris suaktyvins užduotis pagal nustatytus tvarkaraščius ir praneša apie įvykdymą ir, galbūt, vykdymo rezultatą. Tokiu atveju mūsų gijų grupės tikslas yra sujungti būtiną gijų skaičių ir suplanuotus darbus vykdyti nepriklausomomis gijomis. Reikalavimai apibendrinti taip:

  • Gija turėtų galėti iškviesti bet kurį savavališką klasės metodą (suplanuotą darbą)
  • Gija turėtų sugebėti grąžinti vykdymo rezultatą
  • Gija turėtų galėti pranešti apie užduoties atlikimą

Pirmasis reikalavimas suteikia galimybę laisvai susieti diegimą, nes tai nepriverčia mūsų įdiegti tokios sąsajos Bėgama. Tai taip pat palengvina integraciją. Pirmąjį reikalavimą galime įgyvendinti pateikdami gijai šią informaciją:

  • Klasės pavadinimas
  • Metodo, kurį reikia naudoti, pavadinimas
  • Parametrai, kuriuos reikia perduoti metodui
  • Perduotų parametrų parametrų tipai

Antrasis reikalavimas leidžia klientui, naudojančiam giją, gauti vykdymo rezultatą. Paprastas įgyvendinimas būtų išsaugoti vykdymo rezultatą ir suteikti prieigos metodą, panašų į „getResult“ ().

Trečias reikalavimas yra šiek tiek susijęs su antruoju reikalavimu. Pranešimas apie užduoties atlikimą taip pat gali reikšti, kad klientas laukia, kol gaus vykdymo rezultatą. Norėdami išspręsti šią galimybę, galime pateikti tam tikrą atgalinio skambinimo mechanizmo formą. Paprasčiausias atgalinio ryšio mechanizmas gali būti įgyvendinamas naudojant java.lang.Object's laukti() ir pranešti () semantika. Arba mes galime naudoti Stebėtojas šabloną, bet kol kas palikime viską paprastą. Jums gali kilti pagunda naudoti java.lang.Twread klasės prisijungti () metodas, bet tai neveiks, nes sujungtas siūlas niekada jo neužbaigia paleisti () metodas ir veikia tol, kol to reikia baseinui.

Dabar, kai turime paruoštus reikalavimus ir apytikslę idėją, kaip įdiegti gijų grupę, atėjo laikas atlikti tikrą kodavimą.

Šiame etape mūsų siūlomo dizaino UML klasės diagrama atrodo taip, kaip pavaizduota žemiau.

Įdiegimas gijų baseinas

Siūlų objektas, kurį ketiname kaupti, iš tikrųjų yra apvalkalas aplink siūlų objektą. Pakvieskime pakuotę „WorkerThread“ klasę, kuri pratęsia java.lang.Twread klasė. Prieš pradėdami koduoti WorkerThread, turime įgyvendinti pagrindinius reikalavimus. Kaip matėme anksčiau, turime įgyvendinti „PoolableObjectFactory“, kuris veikia kaip gamykla, kad sukurtume mūsų telkiamą „WorkerThread“s. Kai gamykla bus paruošta, mes įgyvendinsime „ThreadPool“ pratęsiant „GenericObjectPool“. Tada mes baigiame savo darbą „WorkerThread“.

„PoolableObjectFactory“ sąsajos diegimas

Mes pradedame nuo „PoolableObjectFactory“ sąsają ir pabandykite įdiegti būtinus mūsų gijų grupės gyvavimo ciklo metodus. Mes rašome gamyklos klasę „ThreadObjectFactory“ taip:

viešoji klasė „ThreadObjectFactory“ įgyvendina „PoolableObjectFactory“ {

public Object makeObject () {return new WorkerThread (); } public void destrObject (Object obj) {if (WorkerThread obj obj) {WorkerThread rt = (WorkerThread) obj; rt.setStopped (true); // Padarykite veikiantį gijos sustabdymą}} viešą loginę reikšmę validateObject (Object obj) {if (objektas WorkerThread) {WorkerThread rt = (WorkerThread) obj; if (rt.isRunning ()) {if (rt.getThreadGroup () == null) {grąžinti klaidingą; } return true; }} return true; } public void activObject (Object obj) {log.debug ("activObject ..."); }

public void passivateObject (Object obj) {log.debug ("passivateObject ..." + obj); if (obj pavyzdys WorkerThread) {WorkerThread wt = (WorkerThread) obj; wt.setResult (null); // Išvalykite vykdymo rezultatą}}}

Išsamiai apžvelkime kiekvieną metodą:

Metodas „makeObject“ () sukuria „WorkerThread“ objektas. Kiekvienos užklausos atveju baseinas tikrinamas, ar reikia sukurti naują objektą, ar pakartotinai naudoti esamą objektą. Pvz., Jei tam tikra užklausa yra pirmoji užklausa, o telkinys tuščias, „ObjectPool“ kvietimai įgyvendinti „makeObject“ () ir prideda „WorkerThread“ prie baseino.

Metodas sunaikinti objektą () pašalina WorkerThread objektą iš baseino, nustatydami Boolean vėliavą ir taip sustabdydami bėgantį siūlą. Vėliau pažvelgsime į šį kūrinį dar kartą, tačiau atkreipkite dėmesį, kad dabar mes kontroliuojame, kaip naikinami mūsų objektai.