2013/04/15

Singletonデザインパターンとjava.lang.ref.Referenceによるキャッシング

皆さんもご存じのとおり、Javaで唯一のインスタンスを使いまわすときは、次のプログラム例のようにSingletonデザインパターンを使います。
またこのプログラムでは、Singletonオブジェクトの生成を遅らせるためにstaticのインナークラスと組み合わせて使っています。「Lazy loading」などと呼ばれている手法です。
/**
 *Lazy loadingを用いたSingletonクラスです。
 */
public class Singleton {
    private Singleton(){}

    /**
     *唯一のインスタンスを返します。
     *@return 唯一のインスタンス
     */
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     *getInstance()を最初に呼び出したときに、SingletonHolderクラスがロードされます。
     *すると、INSTANCEフィールドにSingletonオブジェクトが代入されます。
     */
    private static class SingletonHolder {
        public static final Singleton INSTANCE = new Singleton();
    }
}
ところがSingletonデザインパターンには、Singletonのクラスを保持しているクラスローダが破棄されない限り、Singletonオブジェクトが生存し続ける問題点があります。そこで、java.lang.refパッケージのAPIと組み合わせる方法を提案します。次のプログラムを見てください。
/**
 *Lazy loadingとjava.lang.refパッケージを用いたSingletonクラスです。
 */
public class Singleton {
    private Singleton() {}

    /**
     *唯一のインスタンスを返します。
     *@return 唯一のインスタンス
     */
    public static Singleton getInstance() {
        synchronized(SingletonHolder.class){
            Singleton referent = SingletonHolder.INSTANCE.get();
            if(referent == null){
                referent = new Singleton();
                SingletonHolder.INSTANCE = new WeakReference<>(referent);
            }
            return referent;
        }
    }

    /**
     *getInstance()を最初に呼び出したときに、SingletonHolderクラスがロードされます。
     *すると、INSTANCEフィールドにSingletonオブジェクトが代入されます。
     */
    private static class SingletonHolder {
        public static Reference<singleton> INSTANCE = new WeakReference<>(new Singleton());
    }
}
WeakReferenceクラスを利用しています。外部プログラムがgetInstance()が返すSingletonオブジェクトを参照していなけなければ、マイナーGCが走るたびにSingletonインスタンスが破棄されるようになります。Singletonインスタンスの寿命が短くなり、Javaヒープの使用量を抑制できるでしょう。ところが、このようなプログラム例を記載した日本語記事が見当たりません。英語記事にはありますが、プログラム例がまちまちで怪しいプログラム例も散見されます。そこでどうしたら安全なSingletonになるかを考えてみたわけです。

WeakReference.get()はガーベジコレクション実行を挟んで、復帰値が変わる点に注意する必要があります。そこで上のプログラムの13行目では、WeakReference.get()の復帰値をreferent変数に代入させ、強参照を保持します。referentがnullだった場合、15行目で新しいリファレントをreferent変数に代入し、強参照を保持します。これによりgetInstance()を実行中にガーベジコレクタが起動しても、リファレントが破棄されるリスクを排除できるはずです。こうして18行目で有効なSingletonオブジェクトを確実に返せるでしょう。たとえば、15~16行目を1文にまとめて「SingletonHolder.INSTANCE = new WeakReference<>(new Singleton())」などとしていけないでしょう。

なお、Singletonインスタンスの寿命を延ばしたければ、16、27行目のWeakReferenceをSoftReferenceに変更すればよいです。SoftReferenceだとSingletonインスタンスがTenured世代領域までに昇進し、メモリ不足になるまで破棄されない点に注意します。

2013/01/17

PowerShellで指定ウィンドウ以外のすべてのウィンドウを閉じる方法

■PowerShellスクリプトの作成

次の内容をcloseOtherWindows.ps1ファイルとして保存します。
function closeOtherWindow($ss){
 $force = $ss[$ss.length-1] -eq 'force'
 $noTargets = @("cmd", "explorer", "sidebar")
 if($force){
  for($i=0; $i -lt $ss.Length-1; $i++){
   $noTargets += $ss[$i]
  }
 }else{
  $noTargets += $ss
 }

 $process = Get-Process *

 if(!!$process){
  foreach($p in $process){
   if($p.MainWindowHandle -ne 0){
    $pname = $p.ProcessName
    if(!($noTargets -contains $p.name)){
     if($force){
      Write-Host "本当にWindowを閉じます: $pname"
      $p.CloseMainWindow()
     }else{
      Write-Host "Windowを閉じます: $pname"
     }
    }
   }
  }
 }
}

closeOtherWindow $args

■スクリプトを実行する

  1. コマンドプロンプトを管理者モードで起動します
  2. Chromeやfirefox以外のプロセスを終了させる場合、次のように起動します
    プロセスは1個以上指定できます
    • PowerShell .\closeOtherWindows.ps1 chrome firefox
  3. 「Windowを閉じます: プロセス名」が出力されるので、どのプロセスを終了することになるか判ります
  4. 終了するプロセスに問題がなければ、引数の最後にforceを追加して再度実行します
    • PowerShell .\closeOtherWindows.ps1 chrome firefox force

■補足

  • 終了できないウィンドウもあります。
  • ウィンドウとして表示していないプロセスは終了させません
  • cmd、sidebarとexplorerのプロセスは終了させません

2012/06/04

「癒しの説教学」を読んで


私は学生時代に不純な動機がきっかけで、聖書にちょっと興味を持った時期がありました。
外国人がたくさん集うプロテスタント系教会に厚かましくも毎週2、3回遊びに行って、
その教会には、右側が英語、左側が日本語というつくりの聖書がたくさん置かれていて、
いろいろな国の外国人から英語を通して聖書の話を伺いました。

旧約聖書(ユダヤ教)と新約聖書(キリスト教)があって、
新約の方はマタイ、ルカ、ヨハネ、マルコという4人の使徒(Acts)による福音書から始まり、
10人だったか12人だったかの使徒の活動記録があり、
何人かの使徒から各民族?へのお手紙(コリント人への手紙など)が続き、
最後にヨハネによる黙示録で締めくくるような構成になっていたかと思います。

旧約と新約では違うことが書いてあることも当時初めて知りました。
たとえば旧約に「目には目にを、歯には歯にを」が書いてある一方、
新約には「右のほっぺを叩かれたら、左のほっぺも差し出せ」と書いてあったりするわけです。
同時に学校でもユダヤ人の強い復讐心は旧約聖書の教えによるものだと解説を受けた気がします。

聖書に頻出する「罪(sin)」は「犯罪(crime)」とは違うし、
「けがれ」という概念の難しいことばもあります。
またイエスは次のような奇跡を起こしたとも書かれています。
  • 耳の聞こえない人を聞こえるようにした
  • 盲の方の目を見えるようにした
  • らい病を治癒した、
前置きが長くなりましたが、
本書の著者は神学校を卒業した牧師さんか宣教師だったか失念しましたが、
宗教活動をされているクリスチャンです。
また障害をお持ちで、ろう問題にも精通しておられ、deafとDeafを使い分けておられました。

本書では上の奇跡を今でも文字通り信じる人が後を絶たず、
てんかんを患った青年がイエスの奇跡を信じて医師の指示された薬の服用をやめたら、
奇跡どころか発作を起こして命を落としてしまったという悲しい話を紹介しています。

障害や病気を持つのは本人に罪や汚れがあるというようなくだりを盲目的に信じると
汚れがある人は教会に入れるべきではないというふうに解釈してしまい、
てんかんの青年のような自滅行動を助長するし、
結果的にキリスト教が逆に障害者や慢性疾患者を排除する反社会的な差別団体につながると・・・。

またアメリカでは、教会などの宗教建築物はADA法の対象外であるため、
車いすを配慮したスロープを取り付けないところが多いことも紹介していました。
(宗教的文化を尊重してADA法から除外しているんでしたっけ?)

こういったキリスト教活動に疑問を呈し、聖書を読むにあたっては
現代技術をもっても不可能なことはイエスが生きていた当時にできていたはずがなく、
イエスが奇跡を起こしたという文面については
当時の時代背景や地理を理解し、
聖書を書いた使徒たちの思惑や翻訳による解釈のずれを考慮すべきということです。

そして新約に散見される障害者や患者の記事を引用し、著者なりの解釈を加えて、
イエスが起こしたという奇跡は、実は障害者や患者当事者を取り巻く社会を
心理的に解決したことを、比喩的に描いたものではないかと。

神父さんや牧師さんが、障害者や慢性疾患者に対して適切な「癒し」を行うには、
こういった適切な解釈のもとで行わなければならないと訴えていました。

私が学生時代に遊びに行った教会でも、イエスが治癒したことについては、
mind的なものだと説教を受けていましたし、
クリスチャンではない私に対しても暖かく教会に迎え入れていたところを見ると、
著者に近い考えだったのかもしれませんね。

本書の最後に差し掛かったころに、
障害者であれ非障害者であれ他人に依存しながら生きているわけですが、
障害者が周りに手話通訳同行や車いすなど生活に必要なことを求めることは
摩擦の原因になり難しい面がある一方、
求めなければ社会から自らを隔離し、ますます孤立化しまうと解説しています。

ここまで読み終わったところで、本の返却日が来てしまい、
不覚にも完読できませんでした…。