Showing posts with label Java SE : 1 New Features JDK 7. Show all posts
Showing posts with label Java SE : 1 New Features JDK 7. Show all posts

February 24, 2014

Project Coin 2

ကျွှန်တော်ပြီးခဲ့တဲ့ အပါတ်တုန်းက Java 7 ၏ ဘာသာရပ်ပိုင်းဆိုင်ရာ ပြုပြင်ပြောင်းလည်းမှု့ များကို ရေးသားနေခဲ့သော Project Coin နှင့် ၎င်း၏ ပြုပြင်ပြောင်းလည်းမှု့အချို့ကို ဖော်ပြခဲ့၏။ Coin အကြွေစေ့၊ အသေးသုံးဆိုသည့်အတိုင်း Java ပရိုဂရမ်မင်းဘာသာရပ် ရေးသားပုံ အစဉ်မပြေမှု့များကို ရေးသားနေသော ပရိုဂျက် ဖြစ်ပါသည်။ ယခုတစ်ခေါက် Java 7 တွင် Project Coin မှ ရေးသားခဲ့သော အသေးစားပြောင်းလည်းမှု့များမှာ အောက်ပါအတိုင်းဖြစ်၏။
  • switch ဝါကျများတွင် String ကို အသုံးပြုလာနိုင်ခြင်း
  • Diamond ပုံစံ ရေးသားမှု့များ
  • ကိန်းများ၏ရေးသားပုံပြောင်းလည်းခြင်းနှင့် ဘိုင်နရီဒေတာများကို ရေးသားလာနိုင်ခြင်း
  • Multi Catch နှင့် ပြန်လည် Throw လုပ်နိုင်ခြင်း
  • try-with-resources ရေးသားပုံ
  • Simplified varargs method invocation
အပေါ်မှ  အချက်၃ခုကို ပြီးခဲ့တဲ့ အပါတ်က ဖော်ပြပြီးဖြစ်ပါ၍၊ ယခုအပါတ်တွင်လည်း ဆက်လက်၍၊ ကျန်နေသေးသော အကြောင်းအရာများကို ဖော်ပြသွားပါဦးမည်။ ကျွှန်တော့်အနေနဲ့ကတော့ ဒီ Java 7 အရောက်မှာ သုံးရလွယ်လာတာကတော့ Multi Catch နဲ့ try-with-resources တို့ဖြစ်သည်ဟု ထင်ပါသည်။ ဆက်လက် လေ့လာသွားပါဦးမည်။


Multi Catch နှင့် ပြန်လည် Throw လုပ်နိုင်ခြင်း

Java ၏ Exception ထိမ်းသိမ်းမှု့သည် လွန်စွာမှ ရှုပ်ထွေးတတ်ပါသည်။ Java ကို စတင်လေ့လာခါစတွင် ဘာလို့ Java မှာ ဒီလောက် Exception တွေများရတာလဲဟု တွေးထင်ခဲ့ဘူးပါသည်။ လက်တွေ့ လုပ်ငန်းခွင် တွင်လည်း ယနေ့တိုင် ဒီ Exception ကို သေသေချာချာနားမလည်ပဲ ရေးသားထားသော ကုဒ်များကို မကြာမကြာတွေ့ရလေ့ရှိ၏။ ဤသို့ ရှုပ်ထွေးရခြင်း အကြောင်းအရင်းတွင် Java တွင် Exception တွေများလွန်းခြင်းနှင့် ထို Exception များကို တစ်ခုစီ ဖမ်းကာ ကွန်တရိုးများကို ရေးသားရန်လိုအပ်ခြင်း တို့ဖြစ်ပါသည်။

သို့ရာတွင် Java 7 အရောက်တွင် Exception များကို တပြိုင်နက်တည်း ဖမ်းစီး၍၊ ကွန်တရိုးများကို ရေးသားလာနိုင်ပါသည်။ Java 6 ၏ ရေးသားပုံဖြင့် jaxp ကို အသုံးပြုကာ xml ဖိုင်ကို ဖတ်၍ DOM အဖြစ် အသုံးပြုပုံကို ရေးသားကြည့်ပါမည်။
 public void doSample() {
  try {
   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document doc = builder.parse(new FileInputStream("file.xml"));
   
  } catch (ParserConfigurationException e) {
   e.printStackTrace();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (SAXException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
အထက်ပါအတိုင်း Document Object Model လေးတစ်ခုကို ရေးသားရန်အတွက် ဤမျှသော Exception များကို ကွန်တရိုးလုပ်ရန် လိုအပ်ခဲ့၏။ သို့ရာတွင် အထက်ပါ ပုံစံမျိုးတွင် Exception ဖြစ်ပေါ်လေ့ရှိသော အကြောင်းအရာများမှာ ခပ်ဆင်ဆင်ဖြစ်ပြီး၊ များသောအားဖြင့် ကွန်တရိုးများကို တူညီစွာ လုပ်ဆောင်လေ့ရှိ ကြသည်။

ဤနေရာတွင် အသုံးဝင်သည်က Multi Catch ဖြစ်၏။ Java 7 အရောက်တွင် အောက်ပါအတိုင်းရေးသား လာနိုင်ပါသည်။
 public void doSample() {
  try {
   DocumentBuilderFactory factory = DocumentBuilderFactory
     .newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document doc = builder.parse(new FileInputStream("file.xml"));

  } catch (ParserConfigurationException | SAXException | IOException e) {
   e.printStackTrace();
  }
 }
Exception များကို | ခံ၍ Block တစ်ခုတည်းတွင် ရေးသားလာနိုင်ပါသည်။ ထို့အပြင် FileNotFoundException သည် IOException ၏ Sub Class ဖြစ်သောကြောင့်၊ IOException ကို ရေးသားထားပါက၊ FileNotFoundException ကို ရေးသားရန် မလိုအပ်တော့ပေ။ Java 6 ထက်စာလျှင် ရေးသားထားသော ကုဒ်များမှာ နည်းပါးသွားပြီး၊ အတော်လေးကို အမြင်ရှင်းလာသည်ကို တွေ့ရပါလိမ့်မည်။ ရှင်းလင်းစွာ ရေးသားနိုင် ခြင်းသည်လည်း Bug များကို နည်းပါးစေနိုင်ပါသဖြင့်၊ လော့ဂျစ်ပိုင်းဆိုင်ရာမှာရော ရေးသားပုံအပေါ်မှာပါ တတ်နိုင်သလောက် ရှင်းလင်းစွာ ရေးသားရန် လိုအပ်လှပေသည်။

ထို့အပြင် Java 6 အထိ တစ်ခါဖမ်းထားသော Exception များကို ထိုအတိုင်း ပြန်လည် Throw မလုပ်နိုင်ခဲ့ပေမယ့် Java 7 အရောက်တွင် အောက်ပါအတိုင်းရေးသားပြီး၊ ပြန်လည် Throw လုပ်နိုင်လာပါမည်။
 public void doSample() throws FileNotFoundException, SAXException,
   IOException, ParserConfigurationException {
  try {
   DocumentBuilderFactory factory = DocumentBuilderFactory
     .newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document doc = builder.parse(new FileInputStream("file.xml"));

  } catch (final Exception e) {
   e.printStackTrace();
   throw e;
  }
 }
Java 6 အထိဆိုလျှင် မက်သတ်ရေးသားချိန်တွင် Throws လုပ်မည့် Exception များထဲတွင် ဖြည့်စွက်ရေးသားထားခြင်း မရှိပါက၊ အထက်ပါအတိုင်း ဖမ်းထားသော Exception ကို ထိုအတိုင်းပြန်ပြီး Throw လုပ်၍မရပေ။ ဤ Java 7 အရောက်တွင်၊ final စာလုံး တစ်လုံးဖြည့်စွက်ရုံနှင့် ထိုအတိုင်း ပြန်ပြီး Throw လုပ်နိုင်မည် ဖြစ်ပါသည်။


Try-With-Resources ရေးသားပုံ

File Stream များကို အသုံးပြုရာတွင်၊ Close လုပ်ဆောင်ချက်များကို ရေးသားရန်မှာ  အလွန် မေ့လွယ်လှပေသည်။ ထို့အပြင် Close လုပ်ဆောင်ချက်ကို ခေါ်ယူရာတွင် IOException ကို ဖြစ်ပေါ်စေတတ်ပါသဖြင့် ကုဒ်များကို ရေးသားရာတွင် အလွန်ရှည်ရှား တတ်ပေသည်။ ဖိုင်တစ်ခုကို ကော်ပီကူးသည့် ပရိုဂရမ်တစ်ခုကို ရေးသားကြည့်ပါမည်။
 public void copy(String pathFrom, String pathTo) {
  InputStream in = null;
  OutputStream out = null;
  
  try {
   in = new FileInputStream(pathFrom);
   out = new FileOutputStream(pathTo);
   byte[] buf = new byte[1024];
   int n;
   
   while((n = in.read(buf)) >= 0) {
    out.write(buf, 0, n);
   }
  } catch (IOException e) {
   System.err.println(e.getMessage());
  } finally {

   try {
    if(in != null)
     in.close();
    
    if(out != null)
     out.close();
    
   } catch (IOException e) {}
  }
 }
တကယ်တမ်းလိုအပ်သည်မှာ စာကြောင်း ၅ မှ ၁၆ အထိသာဖြစ်သော်လည်း၊ အောက်ပိုင်း စာကြောင်းများမှာ Close လုပ်ရန်အတွက် မဖြစ်မနေရေးသားရသော စာကြောင်းများဖြစ်ပါသည်။ သို့ရာတွင် Java 7 အရောက်တွင် အထက်ပါကုဒ်များကို ရေးသားရန်မလိုပဲ ရှင်းလင်းစွာရေးသားနိုင်ရန် ဖြစ်လာပါသည်။
 public void copy(String pathFrom, String pathTo) {
  
  try (InputStream in = new FileInputStream(pathFrom);
   OutputStream out = new FileOutputStream(pathTo)) {

   byte[] buf = new byte[1024];
   int n;
   
   while((n = in.read(buf)) >= 0) {
    out.write(buf, 0, n);
   }
  } catch (IOException e) {
   System.err.println(e.getMessage());
  }
 }
အထက်ပါအတိုင်း try ဝါကျအတွင်းတွင် အသုံးပြုမည့် Resource များကို ဖြည့်ရေးထားပါက၊ တကူးတက Close လုပ်ရန်မလိုအပ်တော့ပေ။ ထို့အပြင် Close လုပ်ရန်မလိုသည့်အတွက် Close လုပ်ခြင်းကြောင့် ဖြစ်ပွားတတ်သော Exception ကွန်တရိုး များကို တစ်ကူးတက ရေးသားရန်မလိုအပ်တော့ပေ။ ကုဒ်အချင်းချင်း ယှဉ်ကြည့်ရုံနှင့် မည်မျှရှင်းလင်းသွားသည်ကို တွေ့မြင်နိုင်ပါသည်။

ဤကဲ့သို့ Try-With-Resources ရေးသားပုံကို အကောင်းအထည်ဖော်နိုင်ရန်၊ Resource Object များတွင် java.lang.AutoCloseable အင်တာဖေစ်ကို ပံ့ပိုးပေးလာခဲ့ပါသည်။ AutoCloseable အင်တာဖေစ်၏ Sub Interface နှင့် ပံ့ပိုးထားသော ကလပ်စ်များမှာ အောက်ပါအတိုင်းဖြစ်၏။

  • java.beans.XMLDecoder
  • java.beans.XMLEncoder
  • java.io.Closeable
  • java.io.ObjectInput
  • java.io.ObjectOutput
  • java.sql.Connection
  • java.sql.ResultSet
  • java.sql.Statement
  • java.nio.channels.FileLock
  • javax.sound.midi.MidiDevice
  • javax.sound.midi.Receiver
  • javax.sound.midi.Transmitter
  • javax.sound.sampled.Line
အထက်ပါ ကလပ်စ်များနှင့် အင်တာဖေစ်များကို အသုံးပြုပါက၊ Close လုပ်ဆောင်ချက်ကို အတွင်းပိုင်းတွင် အလိုအလျှောက် လုပ်ဆောင်ပေးနိုင်မည် ဖြစ်သည်။ တဖန် AutoCloseable အတွက်လည်း Throable ကလပ်စ်အတွင်းတွင် addSupressed နှင့် getSupressed လုပ်ဆောင်ချက်များကို ဖြည့်စွက်လာတာကို တွေ့ရပါတယ်။


Simplified Varargs Method Invocation

Varargs များသည် J2SE 5.0 တွင် စတင်အသုံးပြုလာနိုင်ခဲ့သော၊ လွန်စွာမှ အသုံးဝင်သော ပုံစံတစ်မျိုး ဖြစ်ပါသည်။ သို့ရာတွင် Varargs များကို အသုံးပြုထားသော Method များကို အသုံးပြုရာတွ အခန့်မသင့်လျှင် ကွန်ပိုင်း Warning များထွက်ပေါ်တတ်ပေသည်။ Arrays#asList လုပ်ဆောင်ချက်သည် varargs ကို အသုံးပြုထားသော မက်သတ်တစ်ခုဖြစ်သည့်အတွက် နမှုနာအဖြစ် အသုံးပြုကြည့်ပါမည်။
package com.mmjug.java7.ep2;

import java.util.Arrays;
import java.util.List;

public class SimplifiedVaragsMethodInvocation {
 List<Integer> intList;
 List<List<String>> strListList;
 
 public void createArrays() {
  // No Warning
  intList = Arrays.asList(1,2,3,4);
  
  // Warning
  strListList = Arrays.asList(Arrays.asList("a","b","c"),
    Arrays.asList("a","b","c"));
 }
}
အထက်ပါကလပ်စ်ကို JDK 1.6 ဖြင့် ကွန်ပိုင်းလုပ်ကြည့်ပါက unchecked သတိပေးချက်ကို ဖြစ်ပေါ်စေမည် ဖြစ်ပါသည်။ သို့ရာတွင် JDK 1.7 ဖြင့် ကွန်ပိုင်းလုပ်ပါက ကွန်ပိုင်း သတိပေးချက် (Warning) မှာထွက်ပေါ်တော့မည် မဟုတ်ပါ။

ဘာကြောင့်လည်းဆိုတော့ Java 7 အရောက်တွင် ကွန်ပိုင်းထွက်သည့်နေရာကို Varargs များကို အသုံးသော Method များ၏ Warning များကို ခေါ်ယူသည့်နေရာမှ Method ရေးသားရာနေရာသို့ ရွှေ့ပြောင်းလိုက်ပြီး၊ ထိုမက်သတ်တွင် @SafeVarargs ဟု Anotation ကို ဖြည့်စွက်ရေးသားလိုက်ခြင်း ကြောင့်ဖြစ်၏။

ယခင်ကဆိုလျှင် Method ကို ခေါ်ယူသည့်နေရာတိုင်းတွင်@SuppressWarnings("unchecked") ဟု ရေးသားရန်ကိုအပ်ခဲ့ပြီး၊ Java 7 အရောက်တွင် Method ရှေ့တွင် @SafeVarargs ဟု တစ်ခါ ရေးသားထားပါက ခေါ်သည့်နေရာများတွင် အကြိမ်ကြိမ် ရေးသားရန် မလိုအပ်တော့ပါ။

ဘာပဲပြောပြော ခေါ်ယူသည့်နေရာတွင် လိုက်ရေးနေရသည် ထက်စာလျှင် တစ်နေရာတည်းတွင် ရေးသားလာနိုင်ခြင်းသည် ကုဒ်ရေးသားသူအနေဖြင့် လွန်းစွာမှ အစဉ်ပြေသော ပြောင်းလည်းမှု့ တစ်ခုဖြစ်ပါသည်။

Java 7 ၏ ဘာသာရပ်ပိုင်းဆိုင်ရာ ပြောင်းလည်းခြင်းများသည်၊ Java 5 ၏ Anotation နှင့် Generics များကဲ့သို့ ထင်ရှားသောပြောင်းလည်းခြင်းများဟု မဆိုနိုင်သော်လည်း၊ Java ကုဒ်များကို ရှင်းလင်းစွာရေးသားနိုင်ရန် အထောက်အကူပြုသော ပြောင်းလည်းမှု့များဟု သုံးသပ်မိပါသည်။ နောက်အပတ်များတွင် API ၏ ပြုပြင်ပြောင်းလည်းခြင်းများဖြစ်သော Java File API အသစ်အကြောင်းကို ဆက်လက်လေ့လာရင်း ဖော်ပြသွားပါဦးမည်။

ကိုးကား
http://itpro.nikkeibp.co.jp/article/COLUMN/20110425/359785/?ST=develop
http://www.docjar.com/html/api/java/util/Arrays.java.html


လေးစားစွာဖြင့်
မင်းလွင်

February 23, 2014

Project Coin

ယနေ့မှာတော့ ပရိုဂရမ်မာ တစ်ယောက်အနေဖြင့် Java 7 ၏ ဘာသာရပ်ပိုင်းဆိုင်ရာ ပြောင်းလည်းမှု့ကို ဆက်လက် လေ့လာ ဖော်ပြသွားပါမည်။ ယနေ့ ဖော်ပြသွားမည့် အကြောင်းမှာမှာ ယခု Java 7 တွင် ပါဝင်ခဲ့သော Project Coin ၏ ပြုပြင်ပြောင်းလည်းမှု့များပဲဖြစ်ပါသည်။ ဒီ Project Coin အကြောင်းကို ပြီးခဲ့တဲ့နှစ်က မြန်မာအိုင်တီပရိုတွင် Open JDK 7 ကိ သုံး၍ ဖော်ပြခဲ့ဘူးပါသည်။ ယခုတော့ JDK 1.7 လည်း တရားဝင် ထုတ်ပြန်ခဲ့ပြီးဖြစ်ပြီး၊ Eclipse မှာလည်း Java 7 ကို တရားဝင် Support လုပ်လာပြီဖြစ်၏။ JDK 1.7 နှင့် Eclipse ကို သုံးပြီး Project Coin ကို ပြန်ပြီး လေ့လာပါဦးမည်။
Project Coin ဆိုသည်မှာ အမည်အတိုင်း အကြွေစေ့၊ အသေးသုံး ဆိုသလို ဘာသာရပ်ပိုင်းဆိုင်ရာ အသေးသုံးပြောင်းလည်းမှု့ များကို ရေးသားနေသော ပရိုဂျက်တစ်ခုဖြစ်ပါသည်။

Java 6 အရောက်တွင် ဘာသာရပ်ဆိုင်ရာ ပြောင်းလည်းမှု့မှာ သိပ်ပြီးထူးခြားမှု့ မရှိခဲ့သော်လည်း၊ Java 7 အရောက်မှာတော့ အတော်လေးကို ပြောင်းလည်းလာသည်ကိုတွေ့ရ၏။ သို့ရာတွင် Java 5 ၏ Generics နှင့် Anotation များကဲ့သို့လည်း ထင်ရှားလောက်သော ပြောင်းလည်းမှု့ များတော့ မဟုတ်ပါ။ သို့ရာတွင် ဤတစ်ခေါက် ပြောင်းလည်းမှု့များသည် ပရိုဂရမ်မာ တစ်ယောက်အနေဖြင့် အသုံးဝင်သော ပြောင်းလည်းမှု့များကို တွေ့ရပါသဖြင့် လွန်စွာမှ အားရမိပါသည်။


switch ဝါကျတွင် String ကို အသုံးပြုလာနိုင်ခြင်း

Java 7 မတိုင်ခင်တွင် switch ဝါကျ၌ byte, char, int, shot များနှင့် ၎င်း၏ Wrapper Class များကိုသာ အသုံးပြုနိုင်ခဲ့၏။ သို့ရာတွင် Java 7 အရောက်တွင် switch ဝါကျ၌ String များကိုပါ အသုံးပြုလာ နိုင်ပါသည်။
public class SwitchSample {

 /**
  * @param args
  */
 public static void main(String[] args) {
  writeChar("one");
  writeChar("two");
  writeChar("four");
 }

 static void writeChar(String str) {
  switch (str) {
  case "one":
   System.out.println("One is comming");
   break;
  case "two":
   System.out.println("Two is comming");
   break;
  case "three":
   System.out.println("Three is comming");
   break;
  default:
   System.out.println(str + " is comming");
   break;

  }
 }

}
အထက်ပါ ကုဒ်များအတိုင်း String များဖြင့် လုပ်ဆောင်ချက်များကို ခွဲခြား၍ ရေးသားနိုင်မည် ဖြစ်၏။ သို့ရာတွင် String ကိန်းရှင်သည် null ဖြစ်ပါက NullPointerException ကို ဖြစ်ပွားစေနိုင်ပါသဖြင့် ကရုပြုစေလိုပါသည်။ အကြောင်းမှာ switch ဝါကျ၏ ပြောင်းလည်းမှု့သည် JVM အဆင့် ပြောင်းလည်းခြင်း မဟုတ်သောကြောင့် ဖြစ်၏။ ကွန်ပိုင်း လုပ်စဉ် ပြောင်းလည်းပေးခြင်း ဖြစ်သောကြောင့် ဖြစ်ပါသည်။ 

ကွန်ပိုင်းလာက ဘယ်လို ပြင်ရေးထားတယ်ဆိုတာကို Class Editor ကို သုံးပြီး ဖွင့်ကြည့်ပါမည်။
// Compiled from SwitchSample.java (version 1.7 : 51.0, super bit)
public class com.mmjug.java7.ep1.SwitchSample {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public SwitchSample();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.mmjug.java7.ep1.SwitchSample
  
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 1, Locals: 1
  public static void main(java.lang.String[] args);
     0  ldc <String "one"> [16]
     2  invokestatic com.mmjug.java7.ep1.SwitchSample.writeChar(java.lang.String) : void [18]
     5  ldc <String "two"> [22]
     7  invokestatic com.mmjug.java7.ep1.SwitchSample.writeChar(java.lang.String) : void [18]
    10  ldc <String "four"> [24]
    12  invokestatic com.mmjug.java7.ep1.SwitchSample.writeChar(java.lang.String) : void [18]
    15  return
      Line numbers:
        [pc: 0, line: 9]
        [pc: 5, line: 10]
        [pc: 10, line: 11]
        [pc: 15, line: 12]
      Local variable table:
        [pc: 0, pc: 16] local: args index: 0 type: java.lang.String[]
  
  // Method descriptor #21 (Ljava/lang/String;)V
  // Stack: 4, Locals: 2
  static void writeChar(java.lang.String str);
      0  aload_0 [str]
      1  dup
      2  astore_1
      3  invokevirtual java.lang.String.hashCode() : int [28]
      6  lookupswitch default: 109
          case 110182: 40
          case 115276: 52
          case 110339486: 64
     40  aload_1
     41  ldc <String "one"> [16]
     43  invokevirtual java.lang.String.equals(java.lang.Object) : boolean [34]
     46  ifne 76
     49  goto 109
     52  aload_1
     53  ldc <String "two"> [22]
     55  invokevirtual java.lang.String.equals(java.lang.Object) : boolean [34]
     58  ifne 87
     61  goto 109
     64  aload_1
     65  ldc <String "three"> [38]
     67  invokevirtual java.lang.String.equals(java.lang.Object) : boolean [34]
     70  ifne 98
     73  goto 109
     76  getstatic java.lang.System.out : java.io.PrintStream [40]
     79  ldc <String "One is comming"> [46]
     81  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
     84  goto 134
     87  getstatic java.lang.System.out : java.io.PrintStream [40]
     90  ldc <String "Two is comming"> [53]
     92  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
     95  goto 134
     98  getstatic java.lang.System.out : java.io.PrintStream [40]
    101  ldc <String "Three is comming"> [55]
    103  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    106  goto 134
    109  getstatic java.lang.System.out : java.io.PrintStream [40]
    112  new java.lang.StringBuilder [57]
    115  dup
    116  aload_0 [str]
    117  invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [59]
    120  invokespecial java.lang.StringBuilder(java.lang.String) [63]
    123  ldc <String " is comming"> [65]
    125  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [67]
    128  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [71]
    131  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    134  return
      Line numbers:
        [pc: 0, line: 15]
        [pc: 76, line: 17]
        [pc: 84, line: 18]
        [pc: 87, line: 20]
        [pc: 95, line: 21]
        [pc: 98, line: 23]
        [pc: 106, line: 24]
        [pc: 109, line: 26]
        [pc: 134, line: 30]
      Local variable table:
        [pc: 0, pc: 135] local: str index: 0 type: java.lang.String
      Stack map table: number of frames 8
        [pc: 40, append: {java.lang.String}]
        [pc: 52, same]
        [pc: 64, same]
        [pc: 76, same]
        [pc: 87, same]
        [pc: 98, same]
        [pc: 109, same]
        [pc: 134, chop 1 local(s)]
}
အဓိက Switch ဝါကျထဲမှာ ဘယ်လိုရေးထားလဲဆိုတာကို ကြည့်ကြည့်ပါမည်။ အဝါရောင်စာလုံးဖြင့် ရေးသားထားသည်ကို ကြည့်ပါ။ ကွန်ပိုင်းလာက String ကို hash အနေဖြင့်ပြောင်းလည်း ပြီးအသုံးပြုသည်ကို တွေ့ရပါမည်။ အကယ်၍ "one" ဆိုပါက switch ဝါကျအတွင်းတွင် "one" ၏ hashCode ဖြစ်သော case 110182: 40 စာကြောင်းကို ရောက်ရှိပြီး စာကြောင်းနံပါတ် ၄၀ ကို သွားမည် ဖြစ်ပါသည်။ အကယ်၍ စာကြောင်းသည် one ဖြစ်ပါက စာကြောင်းနံပါတ် ၇၆ ကို ဆက်သွားပါမည်။ မဟုတ်ပါက စာကြောင်း ၁၀၉ကိုသွားပါမည်။

စာကြောင်းနံပါတ် ၇၆ကိုကြည့်ပါ။ "one is comming" ဆိုတဲ့ စာကြောင်းကို ရေးသားစေပြီး၊ နောက်ဆုံးတွင် စာကြောင်း ၁၃၄ကိုသွားပြီး return လုပ်နေပါသည်။

အားလုံးကို ခြုံပြီး ကြည့်မည်ဆိုပါက String ကို hashCode အနေနဲ့ပြောင်းပြီး Switch လုပ်ပါသည်။ ပြီးမှ တဆင့်ချင်း if else ဖြင့် လမ်းများကို ခွဲခြားအလုပ်လုပ်စေခြင်းသာဖြစ်၏။ ကွန်ပိုင်းလာမှ တဆင့်ပြောင်းပြီး String များကို Switch လုပ်နိုင်အောင် ဖန်တီးပေးနေခြင်းသာဖြစ်၏။ တကယ်တမ်းကျတော့ int ကိုသာ Switch လုပ်နေသည်ကို တွေ့ရပါသည်။ ထို့အတွက် အသုံးပြုမည့် String သည် null ဖြစ်နေပါက၊ String အား hashCode ကို ပြောင်းချိန်မှာ NullPointerException နဲ့တွေ့ရမည် ဆိုသည်ကို သိရှိနိုင်ပါသည်။


ကိန်းဂဏာန်းများအား ဖော်ပြပုံပြောင်းလည်းမှု့

Java ဘာသာရပ်တွင်လည်း C ကဲ့သို့ပင် ကိန်းဂဏာန်းများ၏ ရှေ့တွင် 0 ကိုဖြည့်ရေးပါက၊ octal digit အဖြစ်၎င်း၊ 0x ကို ဖြည့်ရေးပါက hexadecimal အဖြစ်၎င်း သတ်မှတ်ရေးသားနိုင်ပါသည်။ သို့ရာတွင် အသုံးများသော binary Digit များအတွက်မှာမူ ရေးသားနိုင်ခြင်းမရှိခဲ့ပေ။

Java 7 အရောက်တွင် Binary Digit များအား အပြည့်ကိန်းများ၏ အရှေ့တွင် 0b သို့မဟုတ် 0B ကိုရေးသားပြီး ဖော်ပြလာနိုင်ခဲ့ပါသည်။ ထို့အပြင် အပြည့်ကိန်းများအကြားတွင် "_" ကို ဖြည့်ရေး လာနိုင်ပါသည်။
package com.mmjug.java7.ep1;

public class NewLiteralSample {
 
 public static void main(String[] args) {
  int a = 4;
  int b = 0b100;
  System.out.println("a == b : " + (a == b));
  
  a+=1_000_000;
  System.out.println(a);
 }
}
အထက်ဖော်ပြပါအတိုင်း 0b100သည် အပြည့်ကိန်း 4 ကို ဖော်ပြနေပြီး၊ စာကြောင်း ၈ကြောင်းမြောက်တွင် a == b ၏ တန်ဖိုးကို ရေးသားစေပါသည်။ a သည်လည်း 4 ဖြစ်၍ b သည်လည်း ဘိုင်နရီပုံစံဖြင့်ဖော်ပြထားသော 4 ဖြစ်ပါသောကြောင့် ဖော်ပြပုံမှန်ကန်ပါသဖြင့် ရလဒ်မှာ true ဖြစ်ပါလိမ့်မည်။ တဖန် စာကြောင်း ၁၀ တွင် a အား a နှင့် 1_000_000 အား ပေါင်း၍ အစားထိုးနေပါသည်။ "_" ကို အသုံးပြုခြင်းအားဖြင့် 1 ၏ နောက်တွင် သုညခြောက်လုံးပါသည်ကို ရှင်းလင်းစွာ မြင်နိုင်ပါသည်။ တန်ဖိုးမှာ 4 + 1000000 ဖြစ်သောကြောင့် 1000004 ဟု အဖြေထွက်ပါလိမ့်မည်။
a == b : true
1000004
တဖန် ကွန်ပိုင်းလုပ်ပြီးသော ဘိုက်ကုဒ်များအား လေ့လာကြည့်ပါမည်။
// Compiled from NewLiterialSample.java (version 1.7 : 51.0, super bit)
public class com.mmjug.java7.ep1.NewLiterialSample {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public NewLiterialSample();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.mmjug.java7.ep1.NewLiterialSample
  
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 3
  public static void main(java.lang.String[] args);
     0  iconst_4
     1  istore_1 [a]
     2  iconst_4
     3  istore_2 [b]
     4  getstatic java.lang.System.out : java.io.PrintStream [16]
     7  new java.lang.StringBuilder [22]
    10  dup
    11  ldc <String "a == b : "> [24]
    13  invokespecial java.lang.StringBuilder(java.lang.String) [26]
    16  iload_1 [a]
    17  iload_2 [b]
    18  if_icmpne 25
    21  iconst_1
    22  goto 26
    25  iconst_0
    26  invokevirtual java.lang.StringBuilder.append(boolean) : java.lang.StringBuilder [29]
    29  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [33]
    32  invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
    35  iload_1 [a]
    36  ldc <Integer 1000000> [42]
    38  iadd
    39  istore_1 [a]
    40  getstatic java.lang.System.out : java.io.PrintStream [16]
    43  iload_1 [a]
    44  invokevirtual java.io.PrintStream.println(int) : void [43]
    47  return
      Line numbers:
        [pc: 0, line: 6]
        [pc: 2, line: 7]
        [pc: 4, line: 8]
        [pc: 35, line: 10]
        [pc: 40, line: 11]
        [pc: 47, line: 12]
      Local variable table:
        [pc: 0, pc: 48] local: args index: 0 type: java.lang.String[]
        [pc: 2, pc: 48] local: a index: 1 type: int
        [pc: 4, pc: 48] local: b index: 2 type: int
      Stack map table: number of frames 2
        [pc: 25, full, stack: {java.io.PrintStream, java.lang.StringBuilder}, locals: {java.lang.String[], int, int}]
        [pc: 26, full, stack: {java.io.PrintStream, java.lang.StringBuilder, int}, locals: {java.lang.String[], int, int}]
}
main မက်သတ်၏ စာကြောင်းနံပါတ် 0 နှင့် 2 ကို ကြည့်ပါ။ စာကြောင်း ၀ တွင် 4 ၏ ဖော်ပြပုံဖြစ်ပြီး၊ စာကြောင်း ၂ တွင် 0b100 အား ဖော်ပြထားခြင်းဖြစ်သည်။ Source ကုဒ်များတွင် တစ်မျိုးစီ ရေးထားသား သော်လည်း ကွန်ပိုင်း လုပ်ပြီးသောအခါ အတူတူပင်ဖြစ်သည်။ ထို့အပြင် စာကြောင်းနံပါတ် ၃၆ ကို ကြည့်ပါ။ 1_000_000 ဖြင့်ရေးသားထားသည်ကို 1000000 ဟု ပြောင်းလည်းပေးပါသည်။ ဤအချက်ကို ကြည့်ခြင်းအားဖြင့် ဤပြောင်းလည်းမှု့သည် JVM အဆင့်ပြောင်းလည်းမှု့မဟုတ်ပဲ ကွန်ပိုင်းလာ အဆင့်တွင် ပြောင်းလည်းပေးမှု့ ဆိုသည်ကို သိရှိနိုင်ပါသည်။


Generics များအား အတိုကောက် ရေးသားခြင်း

Java 5 မှစတင် အသုံးပြုလာနိုင်သော Generics များသည် Java ဘာသာရပ်၏ Collection များနှင့် နေရာအမျိုးမျိုးတွင် အသုံးပြုလာခဲ့ကြ၏။ Generics အား အသုံးပြုခြင်း အားဖြင့် မလိုအပ်သော ပုံစံပြောင်းခြင်း (Cast) အား လျှော့ပါးစေပါသည်။ သို့ရာတွင် Generics အားအသုံးပြုရာတွင် Object အားသတ်မှတ်သည့် ဘယ်ဘက်တွင်၎င်း၊ ညာဘက်ရှိ Constructor ကို ရေးသားရာတွင်၎င်း Generics ၏ ပါရာမီတာကို ရေးသားရန် လိုအပ်ခဲ့သည်။
aimport java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class GenericsSaple {

 List<String> strList = new ArrayList<String>();
 List<Map<String, List<String>>> mapList = new ArrayList<Map<String, List<String>>>();
}
အထက်ပါ Java 5 တွင် ရေးသားပုံကို ကြည့်ပါ။ ပါရာမီတာများလာပါက ပို၍ ရှုပ်ထွေးလာပါသည်။ Java 7 အရောက်တွင် ညာဘက် Constructor ၏ ပါရာမီတာများကို ရေးသားစရာမလိုအပ်တော့ပေ။ <> ဟု ရေးသားရုံနှင့် အသုံးပြုလာ နိုင်ပါသည်။ <> ရေးသားပုံအား Diamond သင်္ကေတဟုလည်း ခေါ်ပါသေးသည်။

အထက်ပါ ကုဒ်များကို Java 7 ရေးသားပုံဖြင့် ပြန်လည် ရေးသားကြည့်ပါမည်။
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class GenericsSaple {

 List<String> strList = new ArrayList<>();
 List<Map<String, List<String>>> mapList = new ArrayList<>();
}
နှစ်မျိုး ယှဉ်ကြည့်ပါမှ မည်မျှအမြင် ရှင်းလာသည်ကို သိရှိနိုင်ပါသည်။ Java 7 အရောက်တွင် Object ကို ဖော်ပြသည့် ဘက်တွင် Generics ၏ ပါရာမီတာကို ရေးသားထားပါက၊ Constructor ဘက်တွင် လိုအပ်သော ပါရာမီတာများကို ကွန်ပိုင်းလာမှ ဖြည့်စွက် နိုင်ပါသည်။

သို့ရာတွင် အောက်ပါအတိုင်းရေးသားထားသော ကုဒ်များအား ကွန်ပိုင်းလုပ်ကြည့်သောအခါ Error ဖြစ်မည် ဖြစ်ပါသည်။
package com.mmjug.java7.ep1;

public class GenericsSaple {

 class Box<T> {
  private T value;
  
  public Box(T t) {
   this.value = t;
  }
  
  public T getValue() {
   return this.value;
  }
 }
 
 public static void main(String[] args) {
  Box<Number> box = new Box<>(30);
 }
}

စာကြောင်း ၁၈ကြောင်းမြောက်တွင် အင်းစတန့်စ်အား ပြုလုပ်သည့်နေရာတွင် ကွန်ပိုင်း အယ်ရာ ဖြစ်ပါလိမ့်မည်။ 30 အား Autoboxing ဖြင့် Object အဖြစ်ပြောင်းလည်းရာတွင် Integer ကို ပြောင်းလည်းမည် ဖြစ်သောကြောင့် Number နေရာတွင် အစားထိုး၍မရသောကြောင့် ဖြစ်ပါသည်။

ကွန်ပိုင်း လုပ်ထားသော Class ဖိုင်အား ဖွင့်ကြည့်ပါမည်။
// Compiled from GenericsSaple.java (version 1.7 : 51.0, super bit)
public class com.mmjug.java7.ep1.GenericsSaple {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public GenericsSaple();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.mmjug.java7.ep1.GenericsSaple
  
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 3, Locals: 1
  public static void main(java.lang.String[] arg0);
     0  new java.lang.Error [16]
     3  dup
     4  ldc <String "Unresolved compilation problem: \n\tType mismatch: cannot convert from GenericsSaple.Box<Integer> to GenericsSaple.Box<Number>\n"> [18]
     6  invokespecial java.lang.Error(java.lang.String) [20]
     9  athrow
      Line numbers:
        [pc: 0, line: 18]

  Inner classes:
    [inner class info: #26 com/mmjug/java7/ep1/GenericsSaple$Box, outer class info: #1 com/mmjug/java7/ep1/GenericsSaple
     inner name: #28 Box, accessflags: 0 default]
}
main method ၏ နံပါတ် ၄ တွင် Error Message ကို ကြည့်ရင် Box ၏ နေရာတွင် Box ကို အစားထိုးနေသည်ကို ဖော်ပြနေပါသည်။

ယခင် တစ်ခေါက်ရေးသားဘူးသည့် အကြောင်းဖြစ်သောကြောင့် Project Coin အား အကျဉ်းချုပ်၍ တစ်ကြိမ်တည်းနှင့် ပြီးအောင်ရေးရန် စဉ်းစားထားသော်လည်း၊ ရေးရင်းနဲ့ အတော်လေးကို ရှည်လာပါသဖြင့် ဤတစ်ကြိမ်တွင် ဤနေရာတွင် ခေတ္တနားပါဦးမည်။ နောက်ရက်များတွင် Project Coin ၏ ပြုပြင်ပြောင်းလည်းမှု့များကို ဆက်လက်ဖော်ပြသွားပါဦးမည်။

လေးစားစွာဖြင့်
မင်းလွင်

July 26, 2012

Fork And Join

Java 7 မထွက်ခင် ပြီးခဲ့တဲ့နှစ် ၂၀၁၁ အလယ်ပိုင်းလောက်တွင် Java 7 အား လေ့လာရင်း Fork And Join Framework အကြောင်းကို မြန်မာအိုင်တီပရိုတွင် ရေးသားခဲ့ဘူးပါသည်။ Fork And Join Framework သည် Parallel Programming ၏ အခြေခံ Framework တစ်ခုဖြစ်ပြီး၊ Core များများနှင့် တစ်ပြိုင်နက်တည်း အလုပ်ကြီးကြီး လုပ်စေလိုသည့်အခါမျိုးတွင် လွန်စွာ အသုံးဝင်သော Framework တစ်မျိုးဖြစ်၏။

CPU တစ်ခုချင်း၏ စွမ်းရည်မှာ လက်ရှိအချိန်အခါတွင် တိုးတက်နှုန်းမှာ ရပ်တန့်လာသည်ကို တွေ့ရပြီး၊ Multi Core CPU များကို တဖြည်းဖြည်း အသုံးပြုလာသည်ကို တွေ့ရပါသည်။ Java သည်လည်း ခေတ်နှင့် အညီ Multi Core အာကီတက်ချာများတွင် အသုံးဝင်သော ဆော့ဖ်ဝဲဒီဇိုင်းဖြစ်သော Parallel Programming ဘက်ကို အားစိုက်လာပါသည်။ Cloud Computing နှင့် VM Ware များအား အသုံးများလာသော ယနေ့အချိန်တွင် Parallel Programming ဘက်ကို ဦးတည်လာရခြင်းမှာ ခေတ်၏ လိုအပ်ချက်တစ်ခု ဖြစ်သောကြောင့် ဖြစ်ပါသည်။

ဒီလောက် အလားအလာရှိသော ပညာရပ်အား ဘာကြောင့် ရေးရင်းတန်းလန်း ရပ်ခဲ့ရသနည်း ဟုဆိုပါက အကြောင်း ၂ချက်ရှိပါသည်။ ထိုစဉ်က ကျွှန်တော်၏ ကွန်ပျုတာမှာ 32bit P4 Windows XP လေး ဖြစ်သောကြောင့်၊ Core များများကို အသုံးပြု၍ ရေးသားရသော အပလီများအား အသုံးပြုပါက ပို၍ လေးသွားသောကြောင့် Fork And Join ၏ အကျိုးအား လုံးလုံး မသိရှိနိုင်သောကြောင့် မတက်သာပဲ နားခဲ့ရပါသည်။ နောက်တစ်ချက်မှာ Fork And Join သည် အစက Project Lambda နှင့် တွဲ၍ Release လုပ်ရန်ရည်ရွယ်ထား၏။ Fork And Join အား ရေးရာတွင် Closure အား အသုံးမပြုပါက ထပ်ချည်းတလည်းလည်း ကုဒ်များအား ရေးရကိန်းရှိသောကြောင့် Closure နှင့် တွဲရေးရန် အစကတည်းက ပြင်ဆင်ထားခဲ့ကြ၏။ သို့သော်လည်း အကြောင်းကြောင်းကြောင့် Java 7 တွင် Closure အား ရေးသားနေသော Project Lambda အား Release မလုပ်နိုင်ခဲ့ကြ။ Java 8 ကျမှ Release လုပ်မည်ဟု ထုတ်ပြန်ခဲ့ကြ၏။ အဲ့လိုနဲ့ပဲ ကျွှန်တော်လည်း Fork And Join အား ဆက်မရေးပဲ ထားခဲ့ပါသည်။

ယခုဆိုလျှင် Java 7 သည်လည်း အတော်လေး အသားကျလာပြီး၊ Java 8 လည်း ထွက်ပါတော့မည်ဟု ဟန်ရေးတပြင်ပြင်လုပ်နေပြီ ဖြစ်သည်။ Fork And Join အား ဆက်လက် လေ့လာသွား ပါဦးမည်။ ယခုတစ်ခေါက်တွင်တော့ နောက်ကြောင်းပြန်သည့် အနေနှင့် မြန်မာအိုင်တီပရိုတွင် ရေးသားခဲ့သည်များကို ပြန်လည် ဖော်ပြပါဦးမည်။



Concurrency မှ Fork / Join ဆီသို့


Java သည် Version 1.0 ကို ထုတ်ပြန်ထားသည့် အချိန်ကတည်းက Thread များကို အသုံးပြုနိုင်ခဲ့၏။ ကျွှန်တော်ကိုယ်တိုင်လည်း ထိုစဉ်အခါက C နှင့် Basic များကို သာအသုံးပြုခဲ့ဘူးပါသဖြင့်၊ Thread တစ်ခုအလုပ်လုပ်နေစဉ် အခြားသော Thread တစ်ခုအား နောက်ကွယ်တွင် အလုပ်ခိုင်း ထားနိုင်ခြင်း အပေါ်တွင် လွန်စွာမှ အံ့သြမိခဲ့၏။

သို့ရာတွင် Thread များကိုအသုံးပြုရာတွင် အခန့်မသင့်ပါက Dead Lock များကို ဖြစ်ပွားစေတတ်ခြင်း၊ Data များကို ပျက်စီးစေတတ်ခြင်း အစရှိသည့် မလိုလားအပ်သော ပြဿနာများကိုလည်း ဖြစ်ပေါ်စေနိုင်ပါသည်။ လွယ်လင့်တကူ အသုံးပြုနိုင်သော်လည်း၊ ကျွမ်းကျင်စွာအသုံးပြုနိုင်ရန် Parallel Processing နှင့်ပတ်သက်သော အသိပညာများကိုလည်း နားလည်ထားရန် လိုအပ်ခဲ့ပါသည်။

အထက်ပါ အကြောင်းအရင်းများကြောင့် Parallel Processing ကို ပို၍လွယ်ကူစွာအသုံးပြုနိုင်ရန် Parallel Processing Framework တစ်ခုဖြစ်သော Concurrency Utilities ကို Java SE 5 တွင် ထည့်သွင်းခဲ့၏။ Concurrency Utilities တွင် Asynchronous Processing API၊ Thread Save လုပ်ပြီးအသုံးပြုနိုင်သော အဆင့်မြင့် Parallel Processing သုံး Collection များ၊ Lock Mechanism နှင့် Atomic Processing အစရှိသည့် Parallel Processing တွင် အသုံးပြုနိုင်သော နည်းပညာများကို အသုံးပြုလာနိုင်စေခဲ့၏။

Concurrency Utilities တွင် Asynchronous Processing များကို အသုံးပြုရာတွင် Executor Interface မှတဆင့် အသုံးပြုနိုင်၏။ တဖန် Thread Pool ကိုလည်း အဆင်သင့်အသုံးပြုနိုင်ရန် ပြင်ဆင်တား၏။ အဲ့ဒီအတွက် Thread Class ကို တိုက်ရိုက်ဆက်သွယ်ရန် မလိုအပ်သောကြောင့် Parallel Processing ကို အသုံးပြုရန်မှာ အရင်ကလောက် ခက်ခဲခြင်းမရှိတော့ပါ။

သို့ရာတွင် Concurrency Utilities ထွက်ပေါ်ပြီးတဲ့နောက်မှာ Hardware ၏ ဖွဲ့စည်းပုံမှာလည်း လွန်စွာမှပြောင်းလည်းခဲ့ပေသည်။ Java SE 5 ထွက်ပေါ်ခဲ့သည့် 2004 ခုနှစ်နောက်ပိုင်းတွင် CPU တစ်လုံးချင်း၏ Clock အရေအတွက်မှာ ထင်သလောက် တိုးတက်ခြင်းကို မမြင်တွေ့ရတော့ပဲ Multi Core Architecture ဘက်ကို ပြောင်းလာခဲ့ပါသည်။ လက်ရှိ အချိန်တွင် အိမ်သုံးကွန်ပျူတာများ မှာတင် အနည်းဆုံး 4 Core အသုံးပြုလာနိုင်ပြီး၊ Server များမှာဆိုလျှင် သည့်ထက်ပို၍များပေမည်။ ဤကဲ့သို့ CPU ၏ ဖွဲ့စည်းပုံပြောင်းလည်းမှု့အပေါ်မှုအပေါ်တွင် Software များဘက်မှ အပြည့်အဝ အသုံးပြုနိုင်ခြင်းမရှိသေးပါ။ တနည်းဆိုသော် အသစ်ပြောင်းလည်းလာသော CPU ၏ ဖွဲ့စည်းပုံနှင့် ကိုက်ညီသော Software များကို ပြင်ဆင်ထားရန် လိုအပ်လာခဲ့ပါသည်။ အဲ့ဒီအတွက် တတ်နိုင်သလောက် Process များကို ခွဲပြီး၊ CPU ၏ Core များကို ညီညီမျှမျှခိုင်းစေရန် လိုအပ်လာခဲ့ပါသည်။

ပြဿနာက ဤနေရာမှစတင်ပါတော့သည်။ Concurrency Utilities ၏ Executor မှာ သေးငယ်သော Process များကို အလုပ်လုပ်စေရာတွင် မကိုက်ညီသောအချက်ပင်ဖြစ်၏။ Executor မှာ လေးလံသော Process များကို အလုပ်လုပ်စေရာမှာ ထူးချွံသော်လည်း၊ သေးငယ်သော Process များကို အလုပ်လုပ်စေရာမှာ မလိုလားအပ်သော Overhead များကိုဖြစ်ပေါ်စေပါသဖြင့် Performance ကို ကျဆင်းစေတတ်ပါသည်။ ဤနေရာတွင် ထွက်ပေါ်လာသည်က Java SE 7 တွင် ပါဝင်ရန် ပြင်ဆင်ထားသော Fork /Join Framework ပဲ ဖြစ်ပါသည်။

Concurrency Utilities သည် JCP ၏ JSR 166 ဖြင့် ဖွဲ့စည်းပုံနည်းပညာများကို သတ်မှတ်ရေးသားခဲ့၏။ Fork / Join Framework သည်လည်း JSR အသစ်ကိုပြုလုပ်ခြင်းမရှိပဲ JSR 166 ကို ပြုပြင်ရေးသားခြင်းအားဖြင့် နည်းပညာများကို သတ်မှတ်ရေးသားလျှက် ရှိ၏။ Concurrency Utilities နှင့် Fork / Join Framework ကို ခွဲခြားနိုင်ရန်၊ Fork / Join Framework ကို JSR 166y ဟု ခေါ်ဆိုလေ့ရှိ၏။ JSR 166y သည်လည်း JSR 166 နှင့်အတူ Mr Doug Lea မှ ဦးစီး၍ ရေးသားလျှက်ရှိပါသည်။


Divide And Conquer Alogrithm


Multi Core CPU များ၏ စွမ်းအားများကို အပြည့်အဝအသုံးချနိုင်ရန် Task များကို တတ်နိုင်သလောက် သေးငယ်အောင် စိတ်ပိုင်းပြီး၊ core အားလုံးကို မျှတစွာ အလုပ်လုပ်ခိုင်းဖို့ လိုအပ်သည် ဟုဖော်ပြခဲ့ပါသည်။ Task များကို စိတ်ပိုင်းရာတွင် လူသိများသည့်နည်းလမ်းမှာ Quick Sort နှင့် Merge Sort Algorithm တွင် အသုံးပြုထားသော Divide And Conquer Algorithm ပဲဖြစ်ပါသည်။


D&C တွင် ပြဿနာတစ်ခုကို ဖြေရှင်းရာတွင်၊ အားလုံးကို တစ်ပြိုင်နက်တည်း ဖြေရှင်းရာ၌ လွန်စွာခက်ခဲနေပါက၊ အစိတ်စိတ်အပိုင်းပိုင်းခွဲ၍ အကြိမ်ကြိမ်ဖြေရှင်း သွားသည့်နည်းလမ်းကို အသုံးပြုပါသည်။ ခွဲစိတ်ထားသော ပြဿနာက ဖြေရှင်းနိုင်လောက်သည့်ပမာဏ လောက်ကိုရောက်သောအခါမ တိုက်ရိုက်ဖြေရှင်းခြင်း ဖြစ်၏။ D&C Algorithm ကို Java ဖြင့် ရေးကြည့်ပါမည်။
Result solve(Problem problem) {
    if (problem ကိုဖြေရှင်းနိုင်သည်) {
        problem ကို တိုက်ရိုက်ဖြေရှင်းမည်;
        return ရလဒ်;
    } else {
        problem ကို problem1 နှင့် problem2 အဖြစ် စိတ်ပိုင်းပါမည်;
        Result result1 = solve(problem1);
        Result result2 = solve(problem2);
        
        result1 နှင့် result2 ကို ပူးပေါင်းမည်;
        return ပူးပေါင်းထားသော ရလဒ်;
    }
}

အကြိမ်ကြိမ် ခွဲကာဖြေရှင်းနေခြင်းပင် ဖြစ်၏။ လုပ်ဆောင်ချက် တစ်ခုကို အကြိမ်ကြိမ်ပြန်လည် အသုံးပြုနေပါသဖြင့် Performance မှာ အားနည်းပါလိမ့်မည်။ ထို့အတွက် Single Thread ကိုအသုံးပြု၍ ဖြေရှင်းလိုပါက အကြိမ်ကြိမ်ပြန်လည် ခေါ်ယူနေသောနေရာကို Loop အဖြစ်ပြောင်းလည်းခြင်း အစရှိသည့် ပြုပြင်ချက်များကို ပြုလုပ်ရန်လိုအပ်ပါသည်။ သို့ရာတွင် အကြိမ်ကြိမ်ခွဲခြားခေါ်ယူခြင်းကို Multi Core များတွင် ခွဲခြားအလုပ်လုပ်စေမည် ဆိုပါက CPU တစ်ခုထဲတွင် အလုပ်လုပ်စေခြင်း မဟုတ်သည့်အတွက် လွန်စွာမှသင့်တော်မည့် နည်းလမ်းဖြစ်ပါသည်။

ကျွှန်တော်တို့ နမှုနာတစ်ခုအဖြစ် အီတလီသင်္ချာပညာရှင် Fibonacci ၏ Fibonacci Number မေးခွန်းတစ်ခုကို ဖြေရှင်းကြည့်ပါမည်။
အထက်ပါ မေးခွန်းကို ဖြေဆိုရန်မှာ Fork / Join Framework ကို မသုံးပဲရေးကြည့်မည် ဆိုလျှင် အောက်ပါအတိုင်း ရေးမည်ဖြစ်သည်။
Fibo.java
public class Fibo {
    
    int n =0;
    
    public Fibo(int n) {
        this.n = n;
    }
    
    public int compute() {
        
        if(n <= 1)
            return n;
        
        Fibo f1 = new Fibo(n-1);
        Fibo f2 = new Fibo(n-2);
        
        return f1.compute() + f2.compute();
    }
    
    public static void main(String [] args) {
        int inter = new Fibo(40).compute();
        System.out.print(inter);
    }
    
}
အထက်ပါ Fibo Class တွင် private field အနေနဲ့ int n ကို ပိုင်ဆိုင်ပါတယ်။ တဖန် Constructor မှာလည်း Argument အနေရဲ့ int n ကို ရယူပြီး၊ private field ကို အစားထိုးနေပါသည်။ compute လုပ်ဆောင်ချက်တွင်လည်း n ၏ တန်ဖိုးက 1 ဒါမှမဟုတ် 1 ထက်ငယ်ပါက n ကို return လုပ်မည်ဖြစ်၏။ သို့မဟုတ်ပါက f1 နှင့် f2 instance ကို new လုပ်ပြီး၊ အသီးသီး တန်ဖိုးကိုရှာပြီး ရလဒ်ကိုပေါင်း၍ return လုပ်မည် ဖြစ်၏။

အထက်ပါ Fibo Class ကို Fork / Join Framework ကို အသုံးပြု၍ ရေးသားကြည့်မည် ဆိုပါက အောက်ပါအတိုင်းရေးသားနိုင်မည် ဖြစ်၏။
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class FiboTask extends RecursiveTask<Integer> {
    
    private final int n;
    
    public FiboTask(int n) {
        this.n = n;
    }

    @Override
    protected Integer compute() {
        if(n <= 1)
            return n;
        
        FiboTask f1 = new FiboTask(n-1);
        f1.fork();
        
        FiboTask f2 = new FiboTask(n-2);
        return f2.compute() + f1.join();
    }
    
   public static void main(String [] args) {
       int result = new ForkJoinPool(Runtime.getRuntime().
            availableProcessors()).invoke(new FiboTask(40));
       System.out.println(result);
   }
    
}
Fork / Join Framework ကို အသုံးပြုရန်အတွက် Process များကို ခွဲရန် RecursiveTask ကို အမွေဆက်ခံရန် လိုအပ်ပါသည်။ တဖန် RecursiveTask ၏ အမွေခံ Class များသည် compute လုပ်ဆောင်ချက်ကို Override လုပ်ရန်လိုအပ်ပေသည်။ အတွင်းပိုင်းတွင်မှု n သည် 1 ထက်ကြီးပါက n-1 နှင့် n-2 ကို ခွဲပြီး FiboTask ဖြင့် တန်ဖိုးကို ပြန်ရှာပါသည်။အထက်ပါ ကုဒ်များထဲတွင် f2 မှာ အကြိမ်ကြိမ်ပြန်ခေါ်ခြင်းဖြင့် တန်ဖိုးကို ရှာဖွေနေပါသော်လည်း f1 မှာမူ fork လုပ်ဆောင်ချက်ကို အသုံးပြု၍ Asynchronous Task အဖြစ်ခွဲခြားပြီး အလုပ်လုပ်စေပါသည်။ ပြီးဆုံးကာမှ join လုပ်ဆောင်ချက်ဖြင့် ရလဒ်ကို ပြန်လက်ခံနေပါသည်။

နောက်ဆုံးတွင် f1 နှင့် f2 တို့၏ ရလဒ်များကို ပြန်ပေါင်း၍ ပြန်ပို့နေခြင်း ဖြစ်၏။ RecursiveTask ကို ခေါ်ယူအသုံးပြုရာတွင် ForkJoinPoll မှတဆင့်ခေါ်ယူရပါသည်။ ဦးစွာ Runtime#availableProcessors ဖြင့် အသုံးပြုနိုင်သော Processer အရေအတွက်ဖြင့် ForkJoinPoll ၏instance ကို ခေါ်ယူပါသည်။ ပြီးပါက ForkJoinPool#invoke ဖြင့် FiboTaskကို အလုပ်လုပ်ခိုင်းနေခြင်းသာပင်ဖြစ်၏။

Before Running Program
 


Running Program
 


JDK7 ဖြင့် ကွန်ပိုင်းလုပ်ပြီး၊ အလုပ်လုပ်ခိုင်းကြည့်သော အခါ အထက်ပါအတိုင်း ဖော်ပြနိုင်သည်ကို တွေ့ရပါမည်။ အထက်ပါ နမှုနာတွင်လည်း တွေ့ခဲ့ကြရသလို Fork / Join Framework သည် Processor များများနှင့် Parallel Processing များကို အလုပ်လုပ်စေရာတွင် အသုံးပြုနိုင်ရန် ပြင်ဆင်ထားသော Framework တစ်ခုဖြစ်ပါသည်။



လေးစားစွာဖြင့်။
မင်းလွင်