Saturday, October 26, 2013

lz init, dc locking, volatile


ამ სტატიაში ვისაუბრებთ შემდეგ თემებზე:
->lazy initialization
->Singleton
->double-checked locking
->volatile (JIT ში და ASM შიც)

Ok, lets start it!...

###  lazy initialization ####

lazy initialization არის ტაქტიკა, როდესაც თქვენ აფერხებთ ობიექტის შექმნას. ამასთან ომპიტიზაციასაც ვაკეთებთ.

class ResourceManager{ 
private Resource resource;
  public Resource getResource(){

    if ( resource == null ){
      resource = new Resource();
    }
    return resource;
  }
}

შევხედოთ სრდედების თვალით, რა შეიძლება მოხდეს. მოვიდა სრედი I , ნახა ობიექტი არის ნალი,  და შექმნა ობიექტი. ამასთან, II სრედმაც ნახა რომ null არის და შექმნა... თუ გვინდა, რომ ორივე სრედს ერთიდაიგივე instance ქონდეს, მაშინ  singleton დაგვჭირდება (ერთერთი GoF Design Pattern იდან).

### singleton Pattern ####
class Resource{
  private static Resource instance;
  public static Resource getInstance(){
    if ( instance == null){
      instance = new Resource();
    }
    return instance;
  }
}

როდესაც აქ მულტი სრედინგით დავიწყებთ ყურებას synchronized დაგჭირდება... მაგრამ, როდესა ერთ სრედი გაეშვება პრობლემა lock-ისა დაგვხვდება....  ამ პრობლემის გადასაჭრელად Double-Checked Locking პატერნი გამოვიყენოთ...

### Double-Checked Locking ###
ამ შემთხვევაში, მეთოდები არ არიან დასინქრონიზირებულები (წინა შემთხვევაში გვქონდა და ლოქის პრობლემა გვქონდა),
არამედ ინსტანსის შექმნის კოდი ჩაჯდება სინქრონიზაციის ბლოკში.


class Resource{

  private static Resource instance;
  public static Resource getInstance(){
    if ( instance == null ){
      synchronized(Resource.class){
        if ( instance == null ){
          instance = new Resource();
        }
      }
    }
    return instance;
  }
}

თუ ერთი სრედი შესული არის სინქრონიზაიის ბლოკში, სხვები დაელოდებიან სანამ ინიციალიზება არ მოხდება.

პრობლემა ისაა რომ ინიიალიზება და ობიექტის შექმნა სხვადასხვა ადგილასაა. ანუ , პრობლემა ისაა, რომ ერთი სრედი სანამ სინქრონიზაციის ბლოკშია, მეორე როდესაც შემოვა  ( და ამასთან იმის გამო რომ instancce==null), ეს სრედი  ეცდება შექმნას ობიექტი... ოოპს! გავიჭედეთ! stuck in the desert! - ფიქრის შედეგად აღმოვაჩენთ , რომ ის არ არის რაც ჩვენ გვიდნა. ნუ, თუ არ ვიფიქრეთ ვერც აღმოვაჩენთ.

(პ.ს ისე ამაზე ინფო დეტალურად Java Concurrency in Practice წიგნში შეგიძლიათ წაიკითხოთ, ეს არის ძალიან ძალიან მაგარი წიგნი, და ყველა პროგტამისტს უნდა ქონდეს წაკითხული. ამაზონზე თან სულ ახლახანს გაიაფდა).

აბა პრობლემას როგორ გადაჭრით? რამდენიმე გზა არსებობს. აი იმ წიგნში მე რომელიც გითხარით, იქ ნახავთ დაწვრილებით ისე ყველაფერს. უცბათ ერთერთ გზას შემოგთავაზებთ:

class Resource{

  private static class ResourceHolder{
    static final Resource instance = new Resource();
  }

  public static Resource getInstance(){
    return ResourceHolder.instance;
  }

}

მოდით გავაგრძელოთ და ეგრედ წოდებული volatile ზე გადავიდეთ და თან ამ თემასაც დავუკავშირებთ.

მოკლედ, იმისათვის რომ volatile ზე ვისაუბროთ, ჯერ ჯავას memory model უნდა ვიცოდეთ, თუ როგორ მუშაობს -  ყველა სრედი, ჯავაში, გამოიყოფს თავის ცალკეულ ადგილს მემორიდან. ანუ თუ კვენ ერთ სტორიჯს გამოვუყობთ ყველაფერს ეშველება - გავიხარებთ ყველანი. ანუ ვიპოვეთ გზა რითიც Virtual Mahine-ს ვაიძულებთ რომ არ შექმნას ტემპორარი კოპოიოები ცვლადების. (მოკლედ, ბევრს აღარ გავაგრძელებ, სიღრმისეულია ეს თემა, და atomc variable ზე ბევრი რამეს დაწერა შეილება - სალაპარაკოს რა გამოლევს, დრო ვთქათ თორე...)

პატარა მგალით მოვიყვანოთ. წარმოიდგინეთ ორი სრედი, ერთში ცვლადს ენიჭება მნიშვნელობა, მეორეშ სრედში ამ ცვლადს ვკითხულობთ პირდაპირ. ეს შეილება მარტივად გამოვიყენოთ სრედის გაჩერებაშიც  (რათქმაუნდა interruptი შეგიძლიათ), მხოლოდ loop დაგვჭირდება.

public void run(){
 while(stop!=true){
  // სრედი არ კვდება
 }
}
ვიზუალურადაც ვაჩვენოთ. ორი სრედი. როდესაც ერთში შეიცვლება მნიშვნელობა, მეორე იგივე STORE დან იღებს. მოკლედ ASM ში როგორ არის იმას დაბლა დავწერ. ჯერ ეს საკმარისია.



ასეთი რამეც შეიძლება გავაკეთოთ (აქაც იგივე გავაკეთე, პროსტა,  ობიექტის რასაც ვანიჭებთ  volatile  არის. სხვა არაფერი). ანუ დარწმუნებული ვართ რომ თუ ერთმა სრედმა მნიშვნელობა მიანიჭა ცვლადს, მეორე ცვლადში ეგრევე აისახება.

class Foo {

  private volatile Helper helper = null;
  public Helper getHelper() {
    if (helper == null) {
      synchronized(this) {
        if (helper == null) {
          helper = new Helper();
        }
      }
    }
  return helper;
}


ახლა JIT ში რახდება ის ვნახოთ. რაც არ უნდა იყს, ვერ გავექცევით, JIT ში ომპტიმიზაცია ასე მოხდება

while (test.loop == true) ;

// გადავა შემდეგ კოდში =>

if (test.loop) { while (true); }


ოკ, და რეალურად მთლიანი STORE შეინახება EAX რეგისტრში.


volatile მდე იქნებოდა:
00000068  test        eax,eax 
0000006a  jne         00000068 

//შემდეგ კი 

00000064  cmp         byte ptr [eax+4],0 
00000068  jne         00000064 

ყოველი სრედი, იგივე მემორიდან ამოიღებს ცვლადის მნიშვნელბოას  (ptr [eax+4])


რა კითხვებიც გექნებად დაწერეთ, არ მოგერიდოთ! :-)

Friday, August 30, 2013

OpenSource Contribution




OpenSource კარგი მექანიზმია, მნიშვნელობა დიდად "შეიძლება" არ აქვს  პროგრამას  Apache License ადევს,  LGPL,  MIT  თუ სხვა- თუმცა ესეც საკამათო თემაა. GPL მაქსიმალურად სცილობს არ არსებობდეს პროგრამა კოდის გარეშე (მაშინ როდესაც შეგიძლია ლოკალური ცვლილებები Apache-ს ლიცენზიით გააკეთო და შენთან დაიტოვო) - რიჩარ სტელმანის მიზანიც Security დან გამომდინარე ის იყო, რომ ყოფილიყო ინტერნეტ სიცრცეში Freedom.  პირადად მე GNU-ს მამას ვეთახმები ამ საკითხსი, და მისი ლიცენზიის პირობებიც ნამდვილად მომწონს.




ერთერთი ყველაზე კარგი გმაოცდილება   პროგრამისტისთვის არის ღია კოდის პროექტებში მონაწილეობაა. აქ მკაცრად დაცულია კოდის სტილი, დიზაინ პატერნები, უფრო მეტიც თავად დაშორებები სიმბოლოებს შორისაც.  

ესენი კი არის ჩემი PATCH ები აპაჩეს პროექტში:

https://issues.apache.org/jira/secure/attachment/12597305/PDFBOX-1690.patch
https://issues.apache.org/jira/secure/attachment/12611618/VisibleSignature.patch
https://issues.apache.org/jira/secure/attachment/12613577/fixed.patch

https://issues.apache.org/jira/secure/attachment/12623115/TSATimeSignature.patch

Friday, August 23, 2013

JVM -D option

JVM ეშვება სისტემ properties ებთან ერთად. ჩვენ კი შეგვიძლია ისინი დავაკონფიგურიროთ -D პარამეტრით. მაგალითად, აპლიკაციის გასაშვება თუ გვინდა პროქსის გავლით, შეგვიძლია მარტივად დავწეროთ:



ან მაგალითად JNLP ვუშვებთ ჯივიემის პარამეტერებით:

ჩვენი კოდიდან კი თუ გვინდა მნიშვნელობის ამოღება:
System.getProperty("developmentMode");

Friday, July 12, 2013

EJB Timer Service API

Timer Service API.


Timer Service ის გამოსაყენებლად იმპლემენტაცია უნდა გავუკეთოთ javax.ejb.TimedObject ინტერფეისს, რომელშიც აღწერილია ქოლბექ მეთოდი ejbTimeout( ):



EJB  ში შეგვიძლია @javax.ejb.Timeout ანოტაციაც დავადოთ მეთოდს, რომელიც voidს აბრუნებს, და ექნება  javax.ejb.Timer პარამეტრი.
აქვე ორივეს ვნახავთ


ალტერნატივა  არი @javax.ejb.Timeout ანოტაცია:


}


იმისათვის რომ დავარეგისტრიროთ ბინი  დროის პერიოდში TimerService –ს ვიყენებთ. TimerService შეგვიძლია inject გავუკეთოთ @javax.annotation.Resource ით ან EJBContext იდან წამოვიღოთ.


ანუ ეს ორი ვარიანტი გვაქვს:
@Resourceprivate SessionContext ctx; ctx.getTimerService();
@Resource javax.ejb.TimerService timerService;


მაგალითად დარეგისტრირებისთვის შევქმნათ  CalendarTimer, ან შეგვილია პირდაპირ IntervalTimer, ანაც SingleActionTimer იც აქვს. დეტალურად API ში შეგიძლიათ ნახოთ, რა რას აკეთებს, აქ რო არ დავწყო მე პოემების წერა. აგერ ლინკიც:  http://docs.oracle.com/javaee/6/api/javax/ejb/TimerService.html  -  Just Google :-)



ტაიმერის წაშლაც ადვილადაა შესაძლებელი, პირდაპირ cancell() მეთოდი აქვს.


აგერ ერთი მაგალითიც  CalendarTimer–ის.



მოლკედ მთავარი მუღამი ისაა, რომ თუ სერვერი დარესტარტდება ან რამე მაგდაგვარი, ტაიმერრი თავის დროს მაინც გააგრძელებს მუშაობას. ანუ რომ შეხვიდეთ Jboss ის ფოლდერში, მაგალითად : /usr/jboss/standalone/data/timer-service-data ფოლდერში
მანდ ნახავთ თქვენს ობიექტებს ტაიმერისას.

რაც შეეხება EJB 3.1 აქ უკვე არის @Schedule ანოტაცია. ძალიან მარტიავად



აგერ XML ითაც შეგვიძლია გავაკეთოთ იგივე @Schedule რომ არ ვწეროთ:


ეს XML კი META-INF ში ჩავაგდოდ – Deployს მერე jar ის META_INF ში ჩახტება;



Thursday, May 23, 2013

Inversion of Control


 შეიელბა ასე გავმარტოთ. Inversion of Control (IoC) და Dependency Injection (DI) პატერნები არიან ყველანი იმისათვის რომ დეფენდენსები არ გქონდეთ თქვენს კოდზე და არხდებოდეს კოდის განმეორებები.  კოდის ოპტიმიზაცი ყოველთვის პრიორიტირებულია ჩვენთვის. ოპტიმიზაციის მთარავი მიზანიც ის არის რომ კოდი ლამაზად და გასაგებად ეწეროს, და ყველაზე მთავარი რაცაა არ ხდებოდის კოდის ხშირი გამეორებები, როდესაც მცირე რამეა შესაცვლელი.

ერთერთი მაგალითი ასეთი შეიძლება მოვიყვანოთ.

გვაქვს List რაღაც A ტიპის ობიექტებით სავსე და მინდა მისი გადაყვანა Map ში. შემდეგ ვაკეთებ ისევ სიას, ოღონდ B ტიპის ობიექტებით სავსეს და მინდა მისი გადაყვანა კვლავ Map ში. ამ შემთხვევაში შეგვიძლია მხოლოდ ერთი მეთოდი გვქონდეს გადაყვანის, არ ვაკეთოთ ტიპებით overload ები. თუ ასეთი 10 ტიპის ობიექტი მექნება, 10 overload არ გავაკეთებ.

მაგალითად, გვაქვს კლასი წიგნებისა.

შევავსოთ იგი:

ახლა დაგვჭირდება ერთი ინტერფეისი, რომელშიც მეთოდის პროტოტიპს ჩავწერთ – მეფითა keyს ამოღებისა. მთავარი პრობლემა ჩვენ ის გვაქვს რომ არ ვიცით ობიექტის key რა იყოს (ზოგ შემთხვევაში რა არის, ზოგში რა). ამიტომ თითოეული ობიექტისათვის გავაკეთოთ კლასი, რომელიც იმპლემენტაციას გაუკეთებს KeyFinder–ს.

მაგალითად ინტერფეისი:


და ჩვენი წიგნებისთვის გვექნება იმპლემენტაცია შემდეგნაირი, თუ Id გვინდა იყოს მეფსი key.


და გვექნება მხოლოდ ერთი მეთოდი, ზოგადი. რომელსაც გადაეცემა სია ნებსმიერი ტიპისა. და ინტერფეისი რომ გავაკეთეთ KeyFinder, აქაც განზოგადებული ტიპებით. მოხდება Mapის შექმნა. შემდეგ გადავუვლით ყველა ელემენტს სიაში, და
სათითაოდ ამოვიღებთ გასაღებს,

კოდს თუ დააკვირდებით ,  KeyFinder   finder გვაქვს, სადაც  KeyFinder ინტერფეისი არის.  resolver აქვს რეფერენსი რომელიმე კლასის ობიექტთან , რომელსიც აკეთებს ინტერფეისი იმპლემენტაციას ––> მას აქვს Overriden მეთოდი გასაღების ამოღებისა ––> მისი დახმარებით , სწორედ ამ ტიპის კლასის ობიექტიდან როგორ ამოვიღოთ გასაღები ვიცით.

თუ დავამატებთ მაგალითად მანქანების კლას. დაგვჭირდება უბრალოდ   CarKeyFinder -ის დაწერა რომელიც იმპლემენტაციას გაუკეთებს KeyFinder-ს. ან მეორე ვარიანტი ისაა რომ პირადპირ მანქანის კლასმა გაუკეთოს იმპლემენტაცია KeyFinder–ს და ცალკე არ გავიტანოთ - ნუ, გემოვნების ამბებია.




MVN Manifest Entries

თუ აღმოჩნდა რომ manifest ფაილის კონფოგურაციისათვის Maven–ის სტანდარტული პარამეტრები არ გყოფნით, იმისათვის რომ manifest თგვენს გემოზე ააწყოთ (თქვენი საკუთარი ველები დაუმატოთ), ამისთვის მავენს აქვს <manifestEntries>  ტეგი.  გამოყენება მარტივია:
<manifestEntries>
      <YOURTAG> value </YOURTAG>
</manifestEntries>

იხილეთ მაგალითაი:

შედეგი კი გვენქება დაახლოებით ასეთი.

Monday, May 20, 2013

Strategy Pattern

Stragegy patern.   ასევე ლიტერატურაში შეიძლება შეგხვდეს მისი სახელწოდეა როგორც  Policy pattern. მისი საშვალებით ალგორითმის ქცევის არჩევა ძალზედ მარტივად ხდება. იმას, თუ რომელი ალგორითმი იქნება გამოყენებული, კლიენტი განსაზღვრავს.

 დამავწყდა მეთქვა, რომ, ეს დიზაინ პატერნი Creational pattern ოჯხს განეკუთნება.

ამ დიზაინ პატერნის სტრუქტურა ასეთია:




როგორც სურათზე ხედავთ, გვაქვს სტრატეგიის ინტერფეისი, რომელთა მრავალი იმპლემენტაცია შეილება გვქონდეს–  მაგალითად გვინდა Payment ის შესრულება. იგი შეიძლება შესრულდეს Visa ელექტრონით, შეიძლება MasterCard -ით.

ალგორითმი უსმენს კლიენტს და იმ იმპლემენტაციას უშვებს რომელიც მოთხოვნას შეესაბამება. მოსმენას და შესაბამის სტრატეგის ალგორითმის გამოძახებას Context  ემსახურება.

დავიწყოთ მაგალითის წერა, და  თან განვმარტოთ. თავდაპირველად, გადახდისთვის გავაკეთოთ enum, რომლებითაც იქნება შესაძლებელი გადახდა. შემდეგ ამ ენამიდან რომელიმეს Context–ს გადავცემთ.  თუ სხვა ჯერზე ფეიმენთის გაკეთება  გადახდის სხვა ტიპით მომინდება, უბრალოდ  კონტექტს ვეტყვი ამ ყოველივეს.



PaymentContext, რომელიც განსაზღვრავს რომელი implement გაუშვას. აქ მარტივადაა ყველაფერი, switch ით ვნსაზღვრავ საჭიროს. როდესაც კონტესტის ობიექტს შევქმნი, კონსტრუქტორშივე ვახდენ შესაბამისი მეთოდის მინიჭებას.


PaymentRule ინტეფეისი ,რომლის შვილებიც იქნებიან კონკრეტული იმპლემენტაციები. ჩვენს შემთვევაში ერთი მასტერქარდთან მომუშავე, მეორე ვიზა ელექტრონთან. სწორედ კონტექსტში  PaymentRule  შვილის რომელიმე ობიექტს ვქმნი (switch ებში), და ვანიჭებ paymentRuleს, რომელიც არის PaymentRule   ტიპისა.


ახლა დავწეროთ კონკრეტული სტრატეგიის იმპლემენტაციები.

ეს VisaElectron იმპლემენტაცია.  ეს კი უკვე MasterCard–ის:


საბოლოოდ კი ყველაფერი ძალიან მარტივი გვაქ.