社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

Java challenge Interface

問題:何が出力されるのか?

public class BigBangTheory {

  public static void main(String[] args) {
	Scientist scientist = new Sheldon() {
	  search() {
		System.out.println("This is my new spot!");
	  }
	};

	scientist.search();
  }
	
  interface Scientist {
	void search();
    }

    static class Sheldon implements Scientist {
	void search() {
            System.out.println("This is my spot.");
	}
    }
}

考え
Sheldon のインスタンス生成時に、search() をオーバーライドしているのだから
「This is my new spot!」と表示されるはず。

答え
コンパイルエラー。。理由↓
1. Sheldon クラス内の search() メソッドのアクセス修飾子の可視性が下がってしまっている。 public -> 指定なし
2. Sheldon のインスタンス生成時における search() メソッドに戻り値の型が指定されていない。

インターフェースのメンバは暗黙的に public になることと、文法の誤りに気付くかどうかですね。
コンパイル通るようにしたら、「This is my new spot!」が表示されました。

広告を非表示にする

Java challenge Integer

問題:何が出力されるのか?

Integer number1 = 5;
Integer number2 = 5;

Integer number3 = 128;
Integer number4 = 128;

// True or False ?
System.out.println(number1 == number2);
System.out.println(number3 == number4);

考え
False, False が出力されるのかなと思いましたが、、、

True, False が出力されました。。

なぜ?
どうも、-128 から 127 は JREがキャッシュするらしく、同じ値が参照されるらしい。
パフォーマンス向上のため?

コード
Java/IntegerChallenge.java at master · blueskyarea/Java · GitHub

広告を非表示にする

マルチスレッドプログラミング - Runnable interface の実装

前の記事では、Thread class を継承する方法を試しました。
マルチスレッドプログラミング - Thread class の継承 - 社内se × プログラマ × ビッグデータ

今回は、Runnable interface を実装することで、マルチスレッドを実現していきます。
f:id:blueskyarea:20170822004014p:plain

こんな感じで作成できます。

public class Dog extends Animal implements Runnable {
}

この実装のメリットとしては、継承するクラスの対象として、Thread クラス 以外を指定することができます。
Runnable インタフェースは、run() メソッドを実装しているので、オーバーライドします。

public class Dog extends Animal implements Runnable {
  @Override
  public void run() {
    // anything task
  }
}

このスレッドを開始するためには、ワーカーとなるクラスのインスタンスを生成して、Threadインスタンスに渡してあげます。
そして、start() メソッドにより開始します。

Dog dog = new Dog();
Thread thread = new Thread(dog);
thread.start();

Thread クラス自体が Runnable インタフェースを実装しています。
それと同じように Runnable インタフェースを実装したクラスを定義してあげていることになります。
Thread クラスに渡してあげることで、start() が使えるようになります。

public class Thread extends Object implements Runnable

まとめ
一つのスレッドを開始するために、最低2つのインスタンスを生成する必要がありますが、Thread 以外のクラスを継承できるのはいいですね。

マルチスレッドプログラミング - Thread class の継承

Apache spark などマルチスレッドのプログラミングを行う上で非常に便利なライブラリが登場していますが、それがあまりにも便利すぎるが故に、それ以前のマルチスレッドプログラミングについても学んでおきたいところです。
そもそも Apache spark のライブラリ自体が、内部的には元来のマルチスレッド手法を踏襲していたりもするところもあると思いますので、やはり知っておいた方が、より理解も深まるだろうと思います。

Java でマルチスレッドプログラミングを行う方法はいくつかあると思いますが、最も基本的な?ものは、Thread クラスを継承して使用するやり方かと思います。
Thread クラスを継承したクラスのインスタンスを生成し、start メソッドを実行することで、新たなスレッドを開始することができます。

f:id:blueskyarea:20170815010150p:plain

以下はどこにでもありそうな簡単なサンプルです。
インスタンス生成時に渡された intervalMs の値 sleep するだけのスレッドです。

public class MyThread extends Thread {
  private long intervalMs;
  private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

  public MyThread(long intervalMs) {
    this.intervalMs = intervalMs;
  }

  @Override
  public void run() {
    System.out.printf(dateFormat.format(new Date()) + " [%s] my-thread startging.\n", Thread.currentThread().toString());
    try {
      Thread.sleep(intervalMs);
    } catch (InterruptedException ie) {
      // nothing to do
    }
    System.out.printf(dateFormat.format(new Date()) + " [%s] my-thread ending.\n", Thread.currentThread().toString());
  }
}

これを main メソッドから呼び出します。
5秒 sleep するスレッドと、10秒 sleep するスレッドを生成しています。

public static void main(String args[]) {
  SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
  System.out.printf(dateFormat.format(new Date()) + " main thread at startging.\n", Thread.currentThread().toString());
  MyThread myThread1 = new MyThread(5000);
  myThread1.start();
  MyThread myThread2 = new MyThread(10000);
  myThread2.start();
  System.out.printf(dateFormat.format(new Date()) + " main thread at ending, actually waiting my-thread ending.\n", Thread.currentThread().toString());
}

結果は以下のようになりました。

01:06:36 main thread at startging.
01:06:36 [Thread[Thread-0,5,main]] my-thread startging.
01:06:36 main thread at ending, actually waiting my-thread ending.
01:06:36 [Thread[Thread-1,5,main]] my-thread startging.
01:06:41 [Thread[Thread-0,5,main]] my-thread ending.
01:06:46 [Thread[Thread-1,5,main]] my-thread ending.

main スレッドは直ちに最後の行に到達していますが、スレッドは直ちに終了はせずに、すべての my-thread が終了するまで待ってくれています。

まとめ

1. Thread クラスを継承した独自のスレッド用のクラスを生成する。
2. run() 内に実際に実行させたい処理を書く。
3. start() でスレッド開始する。

ダイレクトバッファについて調べる機会

きっかけは、Apache spark でアプリケーション動かしていた時に、java.lang.OutOfMemoryError: Direct buffer memory に出くわしたこと。
ダイレクトバッファのこともよく理解せずに、spark プログラミングするのは申し訳ない気持ちになったので。。

ダイレクトバッファとは

  • ダイレクトバッファは、NIOで新しく導入された機能。
  • 「ヒープ」外のメモリ領域に作成される。
  • 「ヒープ」上に作成される通常のバッファ(非ダイレクトバッファ)に比べて高速。
  • ダイレクトバッファはByteBufferについてのみ作成可能。
  • 高速に入出力できるが、作成や削除の処理は非ダイレクトバッファより時間がかかる。
  • 容量の大きいバッファが必要なとき、作成したバッファを繰り返し使用するときに使用するべき。
バッファとは
  • プリミティブ型のデータを保存するための入れ物。
  • バッファクラス(ByteBuffer, IntBuffer など)は、boolean型以外のすべてのプリミティブ型に対して用意されている。
  • バッファクラスは、java.nioパッケージに属していて、java.nio.Bufferクラスを継承している。

f:id:blueskyarea:20170811004848p:plain

NIO(New I/O)とは
  • JDK1.4で追加された機能。java.ioパッケージの入出力機能を補足する。
java.ioパッケージとは
  • データ入出力用のクラスがまとめられているパッケージ。

ダイレクトバッファをつくってみる

ダイレクトバッファの作成

ByteBuffer bufferA = ByteBuffer.allocateDirect(5);

非ダイレクトバッファの作成

ByteBuffer bufferB = ByteBuffer.allocate(5);

Java/TryDirectBuffer.java at master · blueskyarea/Java · GitHub

ダイレクトバッファは作成遅いが、アクセス速い
-- allocate direct buffer --
1002647 nano seconds
-- allocate non-direct buffer --
80622 nano seconds
-- access to direct buffer 100000 times --
16322116 nano seconds
-- access to non-direct buffer 100000 times --
29337490 nano seconds

上記の結果から、以下の点について軽く確認できました。

  • ダイレクトバッファは、非ダイレクトバッファよりも作成に時間がかかる。
  • ダイレクトバッファは、非ダイレクトバッファよりも繰り返されるアクセスに対して速い。

そういえば、ダイレクトバッファは「ヒープ外」に存在するのだから、GCの対象外になるはず。
なので、十分に大きな値を上限値として割り当てることが推奨されるのかもしれない。

Java challenge どこに違和感を感じればよかったのかが分からない

以下のコード、コンパイル通ると思いますか?っていうもんだい。

public class PolymorphismChallenge {
	
public static void main(String[] args) {
	System.out.println(new Chris().getCharacter().getSimpleName());
	}
	
	abstract static class STARSSoldier {
		public STARSSoldier getCharacter() {
			return new Chris();
		}
	}
	
	static class Chris extends STARSSoldier {
		@Override
		public Chris getCharacter() {
			return new Chris();
		}
	}
}

Java/PolymorphismChallenge.java at master · blueskyarea/Java · GitHub

1.Chris インスタンスが生成される。
2.getCharacter() が呼ばれ、Chris インスタンスが返却される。

これだけなので、とくにコンパイルは通るように思えます。
話をややこしくしようとしているのは、Chris が STARSSoldier を継承しているところだと思います。
ただ、それも単純に考えれば、親クラスのメソッドをオーバーライドしているだけです。

実際、このコードを実行してみると、コンパイルは通って以下の出力が得られました。

Chris

ひっかけ問題があった時、するどい方は何でひっかけようとしているのかまで分かると思いますが、この問題に関してはそのようなところに想像が至らなかった。
まだまだ修行がたりない。

VirtualBox ゲストOS のネットワークが頻繁に Up/Down していたが NATネットワークに変えたら解消

この記事の続きになります。
http://blog.hatena.ne.jp/blueskyarea/blueskyarea.hatenablog.com/entries

ネットワークが毎分切断するような状況だと、ダウンロードするにも途中で切れるから毎度再開しないといけないし、再開モードが機能しない場合は、そもそもダウンロードを完了させることが非常に困難な状況になってしまったので、続けて調べていたところ公式ページに回答がにありました。
#13839 (ethernet frequently disconnecting / reconnecting after upgrade to 4.3.22 => Fixed in SVN) – Oracle VM VirtualBox

同じような状況下になった人は、ネットワークアダプタの設定を NATネットワークに変更することで解消したとのこと。
私は NAT で設定していたので、わらにもすがる気持ちでためしてみたところ、「切れない! ログにも LINKUP、DONW 出ていない! これで数分間のダウンロードにたえられる!」ということになりました。
まぁ、なんとか普通に使えるようになっただけではあるのですが。

これは VirtualBox 4.3.22 の問題だったようですね。
このバージョンで以前は問題なく使用していたので、VirtualBox の問題とは思っていませんでした。
可能性をもっと広げれば、もう少し早く解決できていたなと思いつつ、普通に使えるようになったことをよろこんでいます。