Going my way

いいなと思ったことをメモしていきます。

XMLの基礎知識メモ(1)


XMLはeXtensible Markup Langageの略。オブジェクトとして管理できるようにデータが記述、定義される。
XMLの目的は、プラットフォームに依存せず、拡張可能で、自己記述的および自己包含的なやり方でデータを表現する方法を提供することである。
XML自体は情報を表示する機能を持っておらず、データとデータ構造についての情報を提供しているに過ぎない。

XMLドキュメントでは整形式=形式が整えられている必要がある。

・すべての開始タグは、対応する終了タグを持たなければならない
・属性値は引用符(")で囲まなければならない
・ドキュメントには重複タグがあってはならない
・タグの記述に予約文字を使う場合は、該当するエスケープシーケンスを使って記述する

このガイドラインに違反しないドキュメントは整形式ドキュメントと言われる。

開始タグと終了タグがペアになったものを「要素」と呼ぶ。

下記の予約文字はエスケープシーケンスを使って書き換えること

<   &lt;
>   &gt;
'   &apos;
"   &quot;
&   &amp;
ドキュメントをロードするときに、[&amp;]は[&]に置き換えられる。

XMLにはデータを記述するため、プラットフォームや言語の違いに制限されること無く、アプリケーション間で情報を容易にやり取りできるのである。

ルート要素とは最も外側に記述する要素のこと。必ず1つでなければならない。

XMLのコメントは

<!-- コメント -->

で記述する。

<![CDATA[  囲まれた部分は解析されない。XMLパーサーはこの部分を無視する    ]]

XMLの文法を定義するにはDTD(Document Type Definition)を作成する必要がある。
DTDには、ドキュメント内に記述する要素、その要素に記述するデータや属性、要素を記述する順序などを指定する命令をひと通り定義する。

DTDXMLパーサーにドキュメントがDTDの定義に対して妥当かどうかを確認させる目的を持つ。
ドキュメントとDTDを関連付けさせるためにはDOCTYPE宣言を使う。

恋するデザインパターン(Iterator編)

デザインパターンIteratorパターンを、彼女がたくさんいるプレイボーイに例えて説明します。
明日のプレイボーイオブジェクトになるために頑張りましょう。

Iteratorとは、何かを1つ1つ数え上げるための機能です。
例えば、あなたがプレイボーイだったとしましょう。

あなたにはたくさんの彼女がいます。

その何人もいる彼女を「彼女リスト」という手帳に書いて、一人ひとり指をさしながら数えていくとします。

この数えるための「指」の働きをするのがIteratorです。

つまり、Iteratorとは、何かの集合体を数え上げるために、「その対象を指し示すもの」の役割を抽象化したものです。

では、Iteratorパターンを実際のコードで見てみましょう。

登場人物は以下の通りです。

・Aggregateさん
→「集合体」を抽象化したインターフェースです。集合体を作る時はこのインターフェースを実装します。

・KanojyoListさん
→手帳に書いた「彼女のリスト」になります。「彼女の集合体」を表すため、Aggregateさんをimplementsします。

・Kanojyoさん
→彼女の要素です。この彼女の振る舞いは「自分の名前を返すだけ」です。本当はスリーサイズをセットしたいのですが・・

Iteratorさん
→「集合体を指し示す」ための機能を抽象化したものです。集合の何かを指差したい機能を作る時は、このインターフェースをimplementsします。

・KanojoListIteratorさん
→彼女リストにある彼女を順に指し示す機能を実装したものです。指し示す機能を作っているので、Iteratorをimplementsします。

・Mainさん
→ここからプログラムが始まります。彼女を持てる限界人数を設定して、彼女リストにどんどん彼女を追加していきます。あなたそのものと考えてもいいでしょう。


それでは、コードを見ていきましょう。

・Aggregateさん

package iterator;

public interface Aggregate {
	public abstract Iterator iterator();
}

ここでは集合体に必須の機能としてIteratorをabstractで定義しておくことで、
どんな集合体のクラスを作ってもAggregateさせimplementsしていれば、必ずiterator機能があることが保証されます。


・KanojyoListさん

package iterator;

public class KanojyoList implements Aggregate {
	private Kanojyo[] kanojyoTachi;
	private int last = 0;
	
	public KanojyoList(int genkaiNinzu) {
		this.kanojyoTachi = new Kanojyo[genkaiNinzu];
	}
	
	public Kanojyo getKanojyoNumber(int index) {
		return kanojyoTachi[index];
	}
	public void addKanojyo(Kanojyo kanojyo) {
		if(last < kanojyoTachi.length){
			this.kanojyoTachi[last] = kanojyo;
			last++;
		}else{
			System.err.println("これ以上彼女を捌ききれません!!");
			System.err.println(kanojyo.getName() + "とは断腸の想いで別れます");
		}
	}
	public int getKanojyoNinzu(){
		return last;
	}
	public Iterator iterator(){
		return new KanojyoListIterator(this);
	}
}

・Kanojyoさん

package iterator;

public class Kanojyo {
	private String name;
	public Kanojyo(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
}

Iteratorさん

package iterator;

public interface Iterator {
	public abstract boolean hasNext();
	public abstract Object next();
}

・KanojyoListIteratorさん

package iterator;

public class KanojyoListIterator implements Iterator {
	private KanojyoList kanojyoList;
	private int index;
	public KanojyoListIterator(KanojyoList kanojyoList){
		this.kanojyoList = kanojyoList;
		this.index = 0;
	}
	
	public boolean hasNext(){
		if(index < kanojyoList.getKanojyoNinzu()){
			return true;
		} else {
			return false;
		}
	}
	public Object next(){
		Kanojyo kanojyo = kanojyoList.getKanojyoNumber(index);
		index++;
		return kanojyo;
	}
	
}

・Mainさん

package iterator;

public class Main {
	private static int genkaiNinzu = 5;
	public static void main(String[] args){
		KanojyoList kanojyoList = new KanojyoList(genkaiNinzu);
		kanojyoList.addKanojyo(new Kanojyo("沙織"));
		kanojyoList.addKanojyo(new Kanojyo("さやか"));
		kanojyoList.addKanojyo(new Kanojyo("志穂"));
		kanojyoList.addKanojyo(new Kanojyo("由利"));
		kanojyoList.addKanojyo(new Kanojyo("明代"));
		kanojyoList.addKanojyo(new Kanojyo("綾"));
		
		Iterator ite = kanojyoList.iterator();
		while (ite.hasNext()) {
			Kanojyo kanojyo = (Kanojyo)ite.next();
			System.out.println(kanojyo.getName());
		}
		
	}
}

実行結果は以下の通り。

これ以上彼女を捌ききれません!!
綾とは断腸の想いで別れます
沙織
さやか
志穂
由利
明代

mainで定義した限界人数を超えてリストに追加しようとしたときは、エラーを吐きます

その下でiteratorで一人ひとりの彼女の名前をなめるように吐き出しています。


このように一つ一つの機能を抽象化して分けることで、プログラム同士が疎結合になります。
あるクラスの変更が、他のクラスに影響を与えづらくなるということです。

また、Interfaceに機能を定義しておけば、それを使う側はinterfaceの機能だけ知っておけば、
機能の中身を見なくても必ずinterfaceにあるメソッドは使うことができると保証されています。

大きなプログラムになるとどこのクラスでどのメソッドを使っているかわからなくなってくるため、
このようにクラスに共通する機能をinterfaceとして抽象化することで、仕様と実装を分離することができます。

使う側は仕様を知っていれば、実装を知らなくても機能を使うことができるのです。

Javaのマルチスレッド、sleep,notify,waitのサンプル

sleepは引数に指定した数値ミリ秒でスレッドを停止します。

package thread;

public class SleepThreadTest {
	public static void main(String[] args){
		for(int i = 0; i < 10; i++){
			System.out.println("Good!");
			
			//sleepメソッドはチェックされる例外なので、try~catchで囲む
			try{
				Thread.sleep(1000);
			} catch(InterruptedException e){
				
			}
		}
	}
}

結果、1秒おきにGood!が表示されます。

Good!
Good!
Good!
Good!
Good!
Good!
Good!
Good!
Good!
Good!


次にnotifyとwaitのサンプル。
何をしているかはコメントを見てみて下さい。

package thread;

public class WaitAndNotifyTest {
	public static void main(String[] args){
		final Kago kago = new Kago();
		new Thread(){
			public void run(){
				try{
					System.out.println("私はカゴに入れるスレッドです。\n 2秒眠ります・・・");
					sleep(2000);
				}catch(InterruptedException e){
					System.out.println("カゴにものを入れるスレッドが起こされました!");
				}
				
				//買い物カゴに200円のモノを5個入れるイメージ
				kago.set(200,5);
			}
		}.start();
		
		new Thread(){
			public void run(){
				try{
					sleep(500);
					System.out.println("カゴにある料金を計算します!");
				}catch(InterruptedException e){
					System.out.println("取り出しスレッドが起こされました");
				}
				System.out.println(kago.calc());
			}
		}.start();
	}
}

class Kago{
	private long price = 0;
	private int quantity = 0;
	
	public synchronized void set(long price, int quantity) {
		this.price = price;
		try{
			Thread.sleep(1000);
		} catch(InterruptedException e){
			
		}
		
		this.quantity = quantity;
		//setが終わったので、waitしているスレッドをたたき起こす
		notify();
	}
	public synchronized String calc(){
		if(price == 0 && quantity == 0){
			
			//waitメソッドもtry~catchで囲む。チェックされる例外
			try{
				System.out.println("カゴに入るまで待ちます・・・");
				//waitが実行されると、notifyされるまで待ち続ける
				wait();
			} catch(InterruptedException e){
				System.out.println("起こされました!!");
			}
		}
		long total = price * quantity;
		return "値段:" + price + "円  × " + quantity + "個 = " + total; 
	}
	
}

結果は以下のとおり、セットが終わるのを待ってから計算が実行されます。

私はカゴに入れるスレッドです。
 2秒眠ります・・・
カゴにある料金を計算します!
カゴに入るまで待ちます・・・
値段:200円  × 5個 = 1000

あなたの生産性を劇的に向上させる25個の方法を紹介します!

MITの石井裕先生がツイッターで下記のURLの記事を昨日から紹介してます。原文のURLは下記です。

http://www.redlemonclub.com/brand-you/25-no-nonsense-ways-to-power-up-your-productivity/

Hiroshi Ishii 石井裕 ‏@ishii_mit
【生産性向上】Power up you productivity http://www.redlemonclub.com/brand-you/25-no-nonsense-ways-to-power-up-your-productivity/ …

この記事はフリーランスの人向けに、生産性を向上させるための日々心がけることをまとめた記事ですが、
これは会社員にも、学生にも、浪人生にも、生産性を上げたい全ての人に役に立つ記事であるように思いました。

「25 No-Nonsense Ways to Power Up Your Productivity」

1.毎日運動をしよう

あえて紹介するまでもないかもしれないが、効率的に仕事をするには、体を適切にケアする必要がある。
もしかしたら、あなたは、

「僕はほとんどコンピューターの前に座って仕事をするだけだから、健全な肉体なんて関係ないよ」
と考えるかもしれない。

しかし、あなたが座りっぱなしの仕事をしているとしても、むしろ体を動かす仕事をしている人以上に運動する必要があるのだ。

少なく見積もっても、1日30分以上の運動が必要だ。

しかしあなたがもし、最も生産的かつエネルギッシュな仕事をしたいのであれば、1日に何度も運動するべきである。
できるなら、各食事の前に10分間の運動するべきだ。


2.十分な睡眠を取ろう

フリーランスで働いている人にとって最も難しいのが、健康的な仕事と健全な睡眠のバランスを取ることである。
専門家がいうには、我々は一日7時間から9時間の睡眠が必要だ。

しかし、もしあなたが深夜まで仕事をしているのであれば、いきなり仕事のスイッチを切って、床につくこおとは難しいだろう。
あなたができる最も良い事は、ベッドで仕事をしないことだ。

眠る1時間前にはPCの電源を切ろう。何にも圧迫されない状態を作ろう。
テレビを避け、その代わりに本を読んだり、散歩したり、家族や友達との会話を楽しもう。
そうすることで、リラックスできるはずだ。


3.よく食べよう

あなたが在宅で仕事をしている場合、食事は非常に大切である。
気付けば1日中、間食してることだってありえるのだ。

仕事を組み立てるように、一日の献立を組み立てよう。

3食しっかり食べて、2回の軽食を取ろう。
健康的な食事を買うように。ジャンクフードの誘惑に駆られないように、家からジャンクフードは消滅させよう。


4,カフェインを取り過ぎないこと

古くからの固定観念で、フリーランスのプロフェッショナルはコーヒーを飲むべきであるという信仰がある。
しかし、それは良い習慣ではない。
カフェインを摂取することで、結果的にはエネルギーが足りなくなり、疲れやすくなる。

カフェインの悪いところばかり言うわけではないが、やめられないというなら、せめて量を減らそう。
朝の一杯のコーヒーだけにして、後は水か緑茶に切り替えよう。


5.シンプルなTo Doリストを作り続けよう

生産性を上げるために最も有効なツールはTo Doリストである。

夜になる前に、To Doリストを作ろう。
そして、一日の目標を明確に頭に刻み込んで、次の朝を迎えよう。

ただし、短くシンプルに、現実的にあなたが達成できそうなものをリストにすること。

一日を通してTo Doリストを見返すこと。
実行できなったことがあれば、翌日のリストに移すこと。
手書きでリストを作成するのが理想的だ。
もしホワイトボードがあるなら、そこにリストを書いても良い。


6.タスクに優先順位をつけよ

To Doリストを作っているときに、タスクの重要度を考えなさい。
こうすることで、あなたは他のタスクをする時間など無いことがわかるだろう。
重要でないタスクは、翌日に回せば良い。



7.それぞれのタスクの時間を計ろう

だらだらとした引き延ばしはあなたの最悪の敵だ。

あなたが一日で完遂できる10のタスクのリストを作るとする。
そして、一日の終わりになって、あなたがそのうちのたった5つしか完遂できていなかったとする。
何が起こったのだろうか?
あなたは取り乱し、何が起こったのかすらもわからないだろう。

そんな事態を防ぐためにも、リストに書いてあるそれぞれのタスクに制限時間を設定しなさい。
そして、タスクの始めにストップウォッチをスタートし、時間を計りなさい。
設定した時間内にタスクを終わらせるように時間を確認すること。
こうすることで、時間のプレッシャーという「締め切り効果」が得られ、生産性を劇的に向上させることができるだろう。


8.長期的な目標を描きなさい

目標は様々な期間で設定されるべきだ(週間、月間、四半期、一年など)
そして、それらは全てリンクするべき(つながっているべき)である。
あなたがすること全てが、年間目標に貢献するものであるべきなのだ。

アクションプラン(行動計画)を作る時は、パソコンやその他の気が散るものから離れよう。
おそらく海辺などに行くと、よりクリアな思考ができるだろう。
一旦アクションプランを作ったら、定期的に見直すこと。
目標を達成するたびに更新し、さらなる目標を考えること。


9.「私は生産的であるだろうか?」

定期的に自らに疑問を投げかけなさい。

「私は生産的であるだろうか?」

「そして、このタスクはどのように私をプロフェッショナルとして成長させるものだろうか?」

と。

この2つの質問はあなたを生産的にしてくれるし、目標に沿った進路から外れないようにしてくれる。
そして、長期的な目標に合致しない不要なタスクを取り除いてくれる。


10.障害を取り除こう

家の中は障害物で溢れている。障害物によって人々の生産性は大きく妨げられている。
インターネットの出現によって、これらの障害は一気に膨れ上がった。

携帯電話、チャット(日本で言う「LINE」や「なかまっぷ」など)、メール、ネットサーフィン、
そして、Facebook。これらは全て使い方を誤ると生産性を大きく損なう。

できるなら、これらの障害を切り離し、PCやスマホがない環境で仕事をしよう。


11.決まった時間で決まったタスクをする

障害物を取り除く過程で、決まったタスクを行う時間を設定しよう。
例えば、メールだ。
メールは最も時間がかかるタスクであると共に、タスク遂行の厄介な障害物でもある。
メールのチェックを一日3回、多くても一日に1時間以内に抑えよう。
これを機にコンスタントにメールをチェックするのをやめよう。
そうすることで、あなたはより生産的に他のタスクに取り掛かることができるのだ。


12.外に出て休憩しよう

私達の多くはSNSやオンラインゲームに15分間の時間を使うことが休憩だと考えている。
だが、これは間違っている。

PCに向かっている仕事に従事しているなら、あなたは外に出るべきだ。
新鮮な空気を吸って、運動をすると頭がすっきりする。

景色を変えることでリフレッシュすることができ、より生産的になれるのだ。


13.スケジュールを定めよ

多くの人は、これを「朝早く始めろ」という意味に取るだろう。
しかしあなたが朝型人間であろうと、夜型人間であろうと、スケジュールを定めよう。
もし1日8時間仕事をしたいなら、時間を2~3個のブロックに分けなさい。
区切った時間の中で、しっかり集中してスケジュールを組み込むのである。


14.きれいにしよう

一日の終わりにあなたの机を整理しなさい。事務仕事はできるだけ早く片付けること。
週に一度、「片付けの書類入れ作業」をTo Doリストに加えなさい。
不要なメールを削除し、全ての完遂したタスクを更新/削除しなさい。


15.瞑想する

静かに瞑想し、思索にふけることの意味を過小評価してはいけない。
神経を深く休めることで、生産性を向上させることができる。

一日に6分だけ、リラックスする時間を作りなさい。
自分の呼吸と周りのものに意識しなさい。

あなたの集中力が高まる効果があるだろう。結果的に
生産性をより向上させることができるのだ。


16.好きな事をしなさい

持っているタスクは嫌なものであっても最後までやり遂げなければならない。
そんなことは皆知っている。

しかし、プロのフリーランスとして生きていくならば、嫌いな仕事は受け入れないよう心がけよう。
そうすることで、より生産的になれるだろう。
情熱を持てない仕事を早く片付けることなどできないのである。


17.ポジティブであれ

たくさんの仕事を抱え込んでいるからといって、それがあなたをガッカリさせるものであってはならない。
世の中にはたくさんの自暴自棄になったフリーランサーがいる。

おそらく、あなたを落ち込ませる何かは、生産性に悪影響を及ぼしている。
だからこそポジティブであるべきだ。

あなたが感謝すべき、ポジティブなものに目を向けよう。
その行為が生産性を大きく向上させる。


18.情報の摂取量を減らそう

オンラインで仕事をしているなら、間違いなく多くのRSSフィードを受信しているだろう。
加えて、あなたの仕事に関係のあるニュースをwebサイトから受け取っているはずだ。

これは素晴らしいことだが、
あなたがこれらの情報を読むために、毎日どれだけ多くの時間を使っているかを考えたことはあるだろうか。

考えみると、これらのニュースだけではなく他にも、
メールやテレビのニュースなど多くの消化すべき情報が溢れていることに気付くだろう。

読む時間を制限しよう。
すると、あなたの能力をより多く実務に割くことができることに気がつくはずだ。


19.より少ないものに集中しよう

色々な仕事にいっぺんに取り掛かるのはやめよう。
意識してみると、重い仕事を処理するために、かなり多くの場合でマルチタスクに通り組んでいることに気付くだろう。

マルチタスクは効率を下げる。なぜなら多くの仕事が複雑に絡みあってしまうからだ。

一度に1つの仕事に集中しよう。
そうすることで、それぞれのタスクに対する生産性が高まるのだ。


20.最も良いものを最後に残そう

私達は嫌な仕事を後に引き延ばしがちだ。

だから、毎日最もつまらない仕事をTo Doリストのトップに持ってこよう。

そして、実際に嫌な仕事から始めるのだ。

こうすることで、嫌な仕事を片付けるだけでなく、
楽しい仕事を一日の終わりに残しておくことで、仕事のモチベーションを高く保つことができるのである。


21.常にメモを携帯しよう

夜中に素晴らしいアイデアを思いついた。もう夜だったので、そのまま寝てしまった。
その翌朝パソコンの前に座ったとき、せっかくの思いついたアイデアがなんだったのか、何も思い出せない!

そんなことにならないように、メモかボイスレコーダーを常に持ち歩こう。
そうすることで二度とアイデアを忘れることはなくなるだろう。


22.毎日着飾ろう

これを聞くと不思議に思うかもしれない。
現に、多くの人々が家で働く場合はシャワーも着替えも必要ないと考えている。
実際、「パジャマを着ながら仕事をする」というのは最も大きな魅力の1つでもある。
しかし、これは大きな落とし穴だ。
毎朝シャワーを浴びて、素敵な服を着ることはあなたのモチベーションと生産性を変化させることだろう。


23.仕事に没頭しよう

「Writer's Block」は、私達が皆、不平を持つ最も有名な神話です。
プロジェクトが始まったならば、どんな小さな準備でもしておかなければならない。

(※注)Writer's Blockは作家が突然話を書けなくなるような症状のことのようです。
http://en.wikipedia.org/wiki/Writer's_block


24.収支計画を立てよう

自営業の場合、どれだけのお金が入って、どれだけ出ていくかを知っておくことが大切だ。
いくら稼ぐ必要があるのか、最低どれだけのお金が必要なのか、計画することだ。

目標を達成した月はお金を取っておいて、緊急時に使えるようにしておこう。
会計士を雇うことも考えてもいいだろう。
収支計画がしっかりしていると、本業の仕事にも集中できるものだ。


25.自分にご褒美をあげよう

やるべき仕事が片付いたときや、行動計画にある目標を達成した時は、自分にご褒美をあげよう。

何か面白いことをして自分に成功報酬を与えることで、モチベーション新たにして、次のプロジェクトに取り掛かることができるのだ。


以上が、生産性を劇的に向上させる25個の方法の紹介になります。
いかがでしょうか。

フリーランスの方だけではなく、会社員の方でも参考になりそうですよね!
日々を生産的に過ごし、仕事を充実させていきましょう。

システム障害を減らすためにできること。やるべきこと。

システム開発に障害は付き物だ。
障害が発生したら現場のエンジニアは夜間だろうと休暇中だろうと、呼び出され、対応を余儀なくされる。
手術台に向かう外科医さながらに、システムの手術をしなければならない。

この障害対応はSEにとって最も不幸なイベントであることに疑いの余地はない。
あまりに多い障害対応は現場のエンジニアを疲弊させ、モチベーションの低下すら招く。

障害を完全に無くすことはシステム屋をやっている限り不可能だが、障害を減らすプロセスを洗練させることはできるはずだ。

ここでは、障害を減らすために組織として行うべきプロセスを考えたい。

プロセスの始まりは「障害の発生」からだ。
ここから見ていこう。

<障害を減らすためにするべきこと>

■障害の発生時
・現象を特定する
ユーザーの目線で、何が起こったのか明確にする。

・障害の内容を記録しておく
いつ、どんな障害が発生して、どんな影響があったのか。どんな対応をして解決したのか。
プロセスを属人化せずにドキュメントに残す。
記録せずに記憶に頼ると、是正案を客観視できず、障害の再発につながる。
障害対応の過程は、第三者が見てもわかるように資料に残すこと。

システムは人より長く組織に残るので、担当者がいなくなっても使える資料にする。

■障害対応のプロセス
①暫定的な対応を行う
まずは火消しを行う。
最低限の機能は動くようにする。

②原因特定
障害は何が原因だったのか特定する。
その際は、三種類の原因を考える。

1.障害を作ってしまった原因。開発時のドキュメント、ソースコードの原因。
2.障害を発見できずに起こしてしまった原因。なぜリリース前に発見できなかったのか。
3.復旧が遅れた場合、その対応の過程のミスの原因を考える。

上記三種類を踏まえて、障害が起こった組織的な原因を発見し、プロセス改善につなげる。

原因を考える際は「なぜ」を繰り返して、深掘りしていくこと。
なぜを考える際は、感覚に頼らずに、実際に起こったことを前提にして行う。
「なんとなくこうじゃないか」ではいけない。

これらの過程は全て文書として必ず記録し、第三者が見ても知識を共有できるようにすること。

第三者が見てわかる資料のポイントは以下の通り。
・日時・場所を記入する
・障害が起こったシステムの箇所を特定する
・障害の報告資料は要約せず、ありのままに残す
・いつ、どこで、どんなタイミングで障害が発生したのか

誰が見てもわかるように書くこと。


以上。

障害を減らすプロセスは、地味で単純で退屈なことかもしれない。
でも、そういう地味な改善にこそ、システムの神様は宿っていると信じている。

Javaのマルチスレッドでオブジェクトをロックする方法(オブジェクトをロックするパターン)

前回はメソッドをロックしましたが、今回はオブジェクトをロックしてみましょう。

やっていることは、スレッド①で彼女の名前をセットして、スレッド②で彼女の名前を取得して表示する、という処理です。

スレッド①で彼女のロックを取得しているので、名前をセットしてからsleepで優雅に眠っていても、他のスレッドの彼女オブジェクトを奪われる心配はありません。

スレッド②は待ちきれずに走りだしても、ロックされているオブジェクトにはアクセスできないのです。
現実でもそうですが、目をつけた女の子は早くロックを取得して他の男からアクセスされないようにしましょう。

package thread;

public class TestThread2 {
	public static void main(String[] args){
		final Kanojyo kanojyo = new Kanojyo();
		new Thread(){
			public void run(){
				System.out.println("スレッド-"+Thread.currentThread().getName()+"が走っています");
				
				//彼女pブジェクとのロックを取得する
				synchronized(kanojyo){				
					//sleepしてみる
					try{
						//ロックを取得したので優雅に2秒間待って・・・
						System.out.println(Thread.currentThread().getName()+"は待機中です・・・");
						sleep(2000);
					}catch(InterruptedException e){}
					
					//彼女の名前をセットする
					kanojyo.setKanojyoName("Shiho");
					System.out.println("彼女の名前をセットしました");
				}
			}
		}.start();
		
		new Thread(){
			public void run(){
				try{
					//上で彼女をロックする前にこっちがロックを取得するのは困るので、一瞬待機
					sleep(20);
				} catch(InterruptedException e){}
				System.out.println("スレッド-"+ Thread.currentThread().getName()+"が走っています");
				//いくらスレッドが走っても、ロックを取られているので、setが終わるまでgetKanojyoName()は実行できない
				synchronized(kanojyo){
					System.out.println("彼女の名前は"+kanojyo.getKanojyoName());
				}
			}
		}.start();
	}
}

class Kanojyo{
	private String name = null;
	
	public void setKanojyoName(String name){
		this.name = name;
	}
	
	public String getKanojyoName(){
		return name;
	}
}


実行結果は必ず以下の順番になります。

スレッド-Thread-0が走っています
Thread-0は待機中です・・・
スレッド-Thread-1が走っています
彼女の名前をセットしました
彼女の名前はShiho

ちなみに、私の彼女の名前がShihoというわけではありませんw

Javaのマルチスレッドでオブジェクトをロックする方法

マルチスレッドアプリケーションでは、同時にアクセスされるのを防ぎ、一連の処理を保証するため、ロックをします。
同時にアクセスされることを防ぐことを同期化といいます。

あるインスタンスに関するsynchronizedメソッドは、一度に1つのスレッドしか実行できません。
synchronizedではないメソッドは、同時に2つ以上のスレッドが実行することができます。


それでは、サンプルを見てみましょう。

package thread;

public class TestThread {
	public static void main(String[] args){
		Ikemen ikemen = new Ikemen(200);
		new Thread(ikemen).start();
		new Thread(ikemen).start();
	}
}

class Ikemen implements Runnable{
	int interval=100;
	int x;
	String girlFriendName;
	
	Ikemen(int interval){
		this.interval = interval;
	}
	
	public synchronized String getGirlFriendsName(){
		x++;
		try{
			Thread.sleep(interval);
		}catch(InterruptedException e){}
		
		girlFriendName = "彼女" + x + "号";
		return girlFriendName;
	}
	
	public void run(){
		for(int i = 0; i < 5; i++){
			System.out.println(Thread.currentThread().getName() + ":" +getGirlFriendsName());
		}
	}
}

実行結果下記の通り。

Thread-1:彼女1号
Thread-0:彼女2号
Thread-1:彼女3号
Thread-0:彼女4号
Thread-1:彼女5号
Thread-0:彼女6号
Thread-1:彼女7号
Thread-0:彼女8号
Thread-1:彼女9号
Thread-0:彼女10号

getGirlFriendsName()メソッドがロックされているため、走っているスレッドから同時にアクセスされることがありません。
なので、各スレッドから同時にアクセスされて、変数に同時に加算されることを防ぐことができます。

では、synchronizedの記述をとったらどうなるでしょうか。

package thread;

public class TestThread {
	public static void main(String[] args){
		Ikemen ikemen = new Ikemen(1);
		new Thread(ikemen).start();
		new Thread(ikemen).start();
	}
}

class Ikemen implements Runnable{
	int interval=100;
	int x;
	String girlFriendName;
	
	Ikemen(int interval){
		this.interval = interval;
	}
	
	//synchronizedを外してみる
	public String getGirlFriendsName(){
		x++;
		try{
			Thread.sleep(interval);
		}catch(InterruptedException e){}
		
		girlFriendName = "彼女" + x + "号";
		return girlFriendName;
	}
	
	public void run(){
		for(int i = 0; i < 5; i++){
			System.out.println(Thread.currentThread().getName() + ":" +getGirlFriendsName());
		}
	}
}

実行結果は以下の通り。

Thread-1:彼女2号
Thread-0:彼女2号
Thread-1:彼女4号
Thread-0:彼女5号
Thread-1:彼女6号
Thread-0:彼女6号
Thread-0:彼女8号
Thread-1:彼女8号
Thread-0:彼女10号
Thread-1:彼女10号

変数に同時アクセスされて、整合性が取れなくなっていることがわかります。

Javaでマルチスレッドの基本のまとめ

スレッドとは

アプリケーションプログラムには、アプリケーションの命令を最初から1つずつ順番に実行するための実行制御があります。
このような実行制御の流れを実行スレッドと呼びます。
すべてのアプリケーションには少なくとも1つの実行スレッドが存在します。
マルチスレッド環境では、複数のスレッドを作成することができます。


Javaは1つのプログラムの中で同時に異なる計算処理を行うことが可能です。
1つの計算書林の単位を1スレッドといい、複数のスレッドを同時に実行させることをマルチスレッドと言います。

スレッドの生成方法
①Threadオブジェクトを作成する
② ①で作成したThreadオブジェクトのstartメソッドを呼び出す。すると、オーバーライドされたrunメソッドが呼び出され、処理が行われる。

①のThreadオブジェクトを作成する方法は2つあります。

方法1.Threadクラスを継承するサブクラスを作成し、サブクラスのオブジェクトを生成する。

方法2.Threadクラスのコンストラクタの引数にRunnableインターフェースを指定し、Threadオブジェクトを生成する。


方法1のサンプルを見てみましょう。

package thread;

public class ThreadSample1 {
	public static void main(String[] args){
		//Threadオブジェクトを生成し、参照する
		MyThread thread = new MyThread();
		//もう一つのThreadオブジェクトを生成し、参照する
		MyThread2 thread2 = new MyThread2();
		
		//mainメソッドも走っています。
		System.out.println("now! main Thread running!!");
		
		//スレッド1を走らせます
		thread.start();
		
		//スレッド2を走らせます
		thread2.start();
		
		for(int i = 0;i < 5; i++){
			try{
				Thread.sleep(100);
			} catch(InterruptedException e){
				
			}
			System.out.println("i =" + i);
		}
	}
}

class MyThread extends Thread {
	public void run(){
		for(int j = 0; j<10000;j++){
			System.out.println("j=" + j);
		}
		
		System.out.println("J run end!!");
	}
}

class MyThread2 extends Thread{
	public void run(){
		for(int k = 0; k<10000; k++){
			System.out.println("k=" + k);
		}
		
		System.out.println("K run end!!");
	}
	
}

Threadクラスを継承したMyThreadとMyThread2クラスをインスタンス化しました。
threadのstart()メソッドを実行することで、MyThreadの中のrunが走り出します。

実行結果はこうなります。

k=4614
j=8480
k=4615
~~~
j=9999
k=7873
J run end!!
~~~
k=9999
K run end!!
i =1
i =2
i =3
i =4

mainのスレッドとMyThreadとMyThreadが並列的に実行されていることがわかります。

次に方法2のパターンを見てみましょう。
>方法2.Threadクラスのコンストラクタの引数にRunnableインターフェースを指定し、Threadオブジェクトを生成する。

package thread;

public class ThreadSample2 {
	public static void main(String[] args){
		Thread thread = new Thread(new Runnable(){
			public void run(){
				for(int i = 0; i <5; i++){
					try{
						Thread.sleep(1);
					}catch(InterruptedException e){}
					System.out.println("run end!");
				}
			}
		});
		
		thread.start();
		
		for(int j=0; j < 500; j++){
			System.out.println("j="+j);
		}
		
		System.out.println("main end!");
	}
}

Runnableインターフェースを実装したクラスのオブジェクトをコンストラクタに指定することでスレッドが生成されます。
startメソッドの呼び出しでスレッドは実行可能な状態になります。

実行結果は以下の通り

~
j=488
run end!
j=489
~
j=499
main end!
run end!

スレッドが並行で走っていることが確認できます。

「なるほど!」と納得した変数名の付け方のルール

CODE COMPLETEを読んで、今まで何気なくつけていた変数名にもきちんと意味があることがわかりました。
印象的だったものを紹介したいと思います。

■変数に名前を付けるときに最も重要なことは、変数が表すものを完全かつ性格に説明するような名前を付けること
・このような変数は「名前を読めばわかる」ので、コメントが不要になる
・ただし、変数名が長くなりすぎてしまう可能性もある。
・変数名の適切な長さは、だいたい8~20文字である。

■修飾子を使って名前を修飾する場合は、修飾子を名前の最後に付ける
・totalRevenueではなく、revenueTotal
・averageRevenueではなく、revenueAvarage
・なぜかというと、変数の意味のほとんどを伝える部分が先頭にあるから。

■ループで用いるi,j,kについて
・i,j,kは単純なループのインデックス以外では使用しない
・ループがネストされて長くなる時は、i.j.kの使用について考え直す

■一時変数に注意
・一時変数はtempやxなどが使われる
・一時変数はプログラマが他の変数に比べて軽く扱うため、エラーの可能性が高まる
・そもそもプログラムの変数のほとんどは一時的なものである。それらのいくつかを一時変数と呼ぶことは、それらの本当の目的を理解していないことの表れである

■ブール変数の命名
・done,error,found,success,ok
・is~を付けるのが好きなプログラマもいる。この方法の利点はあいまいな名前では意味不明になることである。
・isDone,isError,isFound,isProcessingCompleteなどはわかるが、isStatusは意味不明になる。

命名規則の大切さ
・プロジェクトで最初に苦労してでも命名規則を作ることに意味がある
命名規則を決めておけば、コードの重要な部分に専念できる。
・コードの一貫性が保てる
・後から読むプログラマが保守しやすい

■省略形のガイドライン
・変数名を短くしたいというのは、初期のコンピューティングの名残である。
C++,Java,Visual Basicなどの現代の言語では名前の長さにはほとんど制限がない。意味のある名前をわざわざ短くする必要はない。
・変数名を省略するなら、ルールを統一すること。


以上。
気になるヒトはCODE COMPLETE(上)を読んでみてください!

【Java】ジェネリックスを使ったサンプルと周辺知識のまとめ

ジェネリックスは何のためにあるの?
コレクション操作において、データ型の不一致をコンパイラに検出させるためです。
コレクションから要素を取得するときは適切なデータ型にキャストする必要があります。
しかし、キャストを指定する際にタイプミスがあっても、コンパイラはそういう問題を検出できません。
ジェネリックスを用いることで、可読性、堅牢性、信頼性を向上させることができます。

ジェネリックスを使わないコードのサンプル

public class NoGenerics {
	public static void main(String[] args){
		List slist = new ArrayList();
		String str = "Hoge";
		slist.add(str);
		String str2 = (String)slist.get(0);
		System.out.println(str2);
	}
}


ジェネリックスを使ったコードのサンプル

public class GenericsSample {
	public static void main(String[] args){
		List<String> list = new ArrayList<String>();
		String st1 = "hoge";
		String st2 = "foo";
		String st3 = "fuga";
		
		Integer i = 555;
		list.add(st1);
		list.add(st2);
		list.add(st3);
		
		//ジェネリックスでStringを指定したコレクションにInteger型をaddしようとすると、
		//コンパイルエラーが発生する。
		//list.add(i);
		
		//拡張for文を使用した取り出し
		for(String st : list){
			System.out.println(st);
		}
		
		System.out.println("--------------------------------");
		//Iteratorを使用した取り出し
		String st = null;
		Iterator<String> itr = list.iterator();
		while(itr.hasNext()){
			st = itr.next();
			System.out.println(st);
		}
	}
}

サンプルの結果は以下の通り。

hoge
foo
fuga
--------------------------------
hoge
foo
fuga


JDK5以降の環境でジェネリックス未使用のコードをコンパイルした場合

C:\temp>javac NoGenerics.java
注:NoGenerics.java の操作は、未チェックまたは安全ではありません。
注:詳細については、-Xlint:unchecked オプションを指定して再コンパイルしてください
。

このように、警告が出力されます。これはただの警告で、コードの実行に影響はありません。

上記でコンパイルが通ったコードはこのようなコードでした。

import java.util.ArrayList;

class NoGenerics {
	public static void main(String[] args){
		ArrayList list = new ArrayList();
		list.add("aaa");
		list.add("bbb");
		list.add(new Integer(1));
		for(Object s : list) {
			System.out.println( ( (String) s).toUpperCase());
		}
	}
}

それで、コンパイルが通ったこのクラスを実行すると・・・

C:\temp>java NoGenerics
AAA
BBB
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer canno
t be cast to java.lang.String
        at NoGenerics.main(NoGenerics.java:9)

このように、キャストのエラーが発生します。
ジェネリックスを使ってコーディングしないとコンパイル時に型のキャストミスによるバグを見逃す可能性が高まります。
ジェネリックスを使用することで、"コンパイル時に"格納したオブジェクトの型をチェックすることができるのです。


型変数名の慣例

型変数名:由来
E:element
K:key
V:value
T:Type


用語の意味
型パラメータ:型パラメータとは、ジェネリックス型の型宣言の中の<>の中の型変数の並びのこと。class HogeのE。
型変数:型変数とは、型パラメータ内に並ぶ変数のこと。ジェネリック方の定義内の型として利用される。
型引数:型引数とは、ジェネリックを使うときに<>に渡す具体的な型のこと。HogeのStringの部分。
パラメータ化された型:型引数を渡された実際に使えるようになった型のこと。Hogeなど。


型パラメータの記述方法
そのクラスとそのサブクラスを許可する
そのクラスとそのスーパークラスを許可する
どのクラスも許可する

System.out.printlnはなぜインスタンス化せずに使えるのか。

Javaプログラマーなら例外なく誰もが使うのが

System.out.println("hoge");

です。

呼吸をするように、ごく自然に使ってきたから、普段は疑問に思うこともなかったのですが、
小便をしているときにふと、こんな疑問が浮かびました。


なんで、System.out.printlnはインスタンス化しなくても使えてるんだ?

てか、この「out.println」の意味はなんだろう?




Javaでは、

import java.lang.*

は暗黙的に行われます。

なので、java.langパッケージの中にあるSystemクラスのうち、staticで宣言されているメソッドはインスタンス化せずとも使えます。

Systemクラスの中を見てみると、PrintStream型のoutが宣言されています。

package java.lang;
public final class System {
	public final static PrintStream out = nullPrintStream();
}

では、PrintStreamクラスの中を見てみると、printlnメソッドはこのように使われています。

    public void println(String x) {
	synchronized (this) {
	    print(x);
	    newLine();
	}
    }

つまり、System.out.printlnとは、

暗黙的にimportされたjava.lang.Systemクラスの、
outが参照するPrintStreamオブジェクトの、
printlnメソッドを使って引数のStringオブジェクトを書き出している。

ということですね。


toStringって何に使うの?
これも生のソースを見たらわかりやすいですが、
Stringクラスのオブジェクトをそのまま返すメソッドですね。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    public String toString() {
	return this;
    }
}

例えば、
String s = "hoge"
System.out.println(s.toString());

とすると、「hoge」と出力されます。



エスケープシーケンス一覧

\n 改行(LF)
\t タブ
\r 改行(CR)
\\ バックスラッシュ
\' シングルクォート
\" ダブルクォート

StringBuilderクラス、エスケープなどまとめ

エスケープ処理とは
特別な文字を使い、後続する文字に別の意味を持たせる処理のこと。

エスケープシーケンスとは
エスケープ処理で表記した文字のこと。

改行文字を含む文字列がほしい場合

String str = "hoge/nfuga";

と書く。すると
hoge
fuga
と出力される。

StringBuilderクラス

StringBuilderクラスとStringクラスはCharSequenceという共通のインターフェースを実装しているため、共通のメソッドを提供する。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

実際にソースをみても、implement CharSequenceってなってるね。


StringBuilderの同値比較
StringBuilderは同じ文字列の内容であっても、StringBuilderオブジェクトとの比較では偽を返す。

StringBuilderで文字列の比較を行う時は、
toStringメソッドでStringオブジェクトに変換してから比較する。

例を以下に示す

package string;

public class UseStringBuilder {
	public static void main(String[] args){
		StringBuilder sb1 = new StringBuilder("abc");
		StringBuilder sb2 = new StringBuilder("abc");
		
		System.out.println("==:"+ (sb1==sb2));
		
		System.out.println("equals:" + (sb1.equals(sb2)));
		
		System.out.println("contentEquals:" + (sb1.toString().contentEquals(sb2)));
	}
}

結果

==:false
equals:false
contentEquals:true

Stringクラスの中の人はけっこう面白かった。

JavaコンパイラJVMという仮想マシン用のマシン語を出力する。

仮想マシンの実行速度は、本物のハードウェアが直接マシン語を実行する場合と比較すると遅くなる(と言われていた)

その後、ホットスポットコンパイルなどの改善を行った。
※ただし、ホットスポットコンパイルが全て良いわけではない。
http://www.atmarkit.co.jp/fjava/rensai3/devedge06/devedge06_1.html

今ではJavaはどちらかというと、実行速度の早い言語と言われている。


Stringクラスについて

よく使われるメソッドのサンプル

package string;

public class MethodOfString {
	public static void main(String[] args){
		//Stringオブジェクトを生成する。
		//Stringオブジェクトは「不変」である。
		String str = "abcdef";
		
		//charAtは指定した位置の文字を取得する。
		System.out.println("charAt(index):"+str.charAt(3));
		
		//lengthは長さを取得
		System.out.println("length:"+str.length());
		
		//indexOfは指定した文字を文字列から検索する
		System.out.println("indexOf:"+str.indexOf("d"));
		
		//substring文字列の一部を取得する。この場合は3文字目から5文字目
		System.out.println("substring(3,5):"+str.substring(3,5));
	}
}

実行結果は

charAt(index):d
length:6
indexOf:3
substring(3,5):de

次に上記のメソッドを使って、メールアドレスのアカウントとドメインを分割してみる。

package string;

public class PrintMailAddress {
	public static void main(String[] args){
		String mailAddress = "hogefugaboofuu@softbank.ne.jp";
		int atMarkIndex = mailAddress.indexOf("@");
		int lastMailAddressIndex = mailAddress.length();
		String account = mailAddress.substring(0,atMarkIndex);
		String domain = mailAddress.substring(atMarkIndex + 1,lastMailAddressIndex);
		
		System.out.println("アカウントは→"+account);
		System.out.println("ドメインは→"+domain);

	}
}

実行結果はこちら

アカウントは→hogefugaboofuu
ドメインは→softbank.ne.jp


文字列リテラルとは
ダブルクォート文字(")で文字の並びを囲んだ表記のこと。

なぜStringはnewしないのか。
Javaの文字列リテラルは暗黙にStringクラスのオブジェクトを生成する。

String str = "hoge";
だったら、
strは"hoge"という文字列リテラルを持つStringオブジェクトを参照する。

例えば、
System.out.println("hoge".getClass());
とすると、
class java.lang.String
が出力される。
"hoge"はStringクラスであるということである。


charAtメソッドの中身
Javaで公開されているコードを見て面白かったので紹介。

    public char charAt(int index) {
        if ((index < 0) || (index >= count)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index + offset];
    }

charAtは、引数の数字で指定した場所にある文字を返すんだけど、
このメソッドの実装からわかるように、Stringクラスは1文字1文字を配列で持っている。
その中の引数で指定した数字の位置にある配列の文字を返すということ。
ちなみに、offsetは文字列の始まりで、普通は0になっている。


Stringクラスのequalsのメソッドの実装内容

    public boolean equals(Object anObject) {
	if (this == anObject) {
	    return true;
	}
	if (anObject instanceof String) {
	    String anotherString = (String)anObject;
	    int n = count;
	    if (n == anotherString.count) {
		char v1[] = value;
		char v2[] = anotherString.value;
		int i = offset;
		int j = anotherString.offset;
		while (n-- != 0) {
		    if (v1[i++] != v2[j++])
			return false;
		}
		return true;
	    }
	}
	return false;
    }
    

Stringはequalsで比較するって言われているけど、じゃあequalsの中で何をやっているのかと言うと、

①引数で指定したオブジェクトがStringクラスのオブジェクトであることを確認。
②Stringクラスが持つ1文字1文字が詰まった配列を順番にマッチングさせていって、一文字でも合わないと
return falseで返しているんだね。

こうやって、実際Stringクラスの中のソースを見ると、メソッドの意味がよくわかって面白い。
まぁ、実装を意識しないで使えるのがオブジェクト指向の良い所なんだけど。

MySQLの文字化けがどうしても直らないときは、my.cnfだけいじってもダメだとわかった。

・my.cnfでいじっても文字化けが直らない。
・INSERTすると文字が化けて見える。
linux自体の文字コードもちゃんとutf-8にした。


どうしてもMySQLの文字化けが直らないから、念のため以下を実行してみた。
すると・・・

mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

下記のコマンドでこれもutf8に変更!
(参考)
http://d.hatena.ne.jp/webtrap/20090922/1253580851
http://ext.omo3.com/linux/mysql_character_set.html

SET character_set_database = 'utf8';

実行したときは変わったんだけど、再起動したらまたlatin1になってしまった。

これはテーブルを作り直すしか無いのかな・・・
(たぶんmy.cnfになんか書けばいいんだけど・・・)
テーブルにデフォルトの文字コードを設定する構文

CREATE TABLE table_name [DEFAULT] CHARACTER SET 'utf8';

これでテーブルを作った後にさらにダメ押しで

SET character_set_database = 'utf8';

で、実際にINSERTしたら、やっと文字化けしなくなった!

さくらVPSにmysqlをインストールしてみた

linuxmysqlをインストール


MySQLがインストールされていないことを確認。

# rpm -qa mysql*

MySQLをインストールする。

# yum install mysql*

MySQLのサービスを開始する。

# /etc/init.d/mysqld start

rootのパスワードを設定する。

# mysqladmin -u root PASSWORD mypassword

MySQLをrootユーザで使い始める

# mysql -u root -p

データベースを作成する。

CREATE DATABASE db1;

データベースの一覧を表示する。

> show DATABASES;

他のユーザを作成し、ユーザ権限を設定する。

CREATE USER gomyownway IDENTIFIED BY 'gomy55';

権限の設定。全権限を与える場合。

GRANT ALL ON db1.* TO gomyownway;

これは、「db1」のデータベース内のすべてのテーブル(*)に対して全権限(ALL)を与える
という意味。

さぁユーザを作ったぞ、早速ログインしようとしたら、こんなエラーが発生。

ERROR 1045 (28000): Access denied for user 'gomyownway'@'localhost' (using password: YES)

なんだよ、ユーザの作り方間違ってたのかよ。
正しくはこう!

mysql>grant all privileges on *.* to 'gomyownway'@'localhost' identified by 'gomy55';

mysql>grant all privileges on *.* to 'gomyownway'@'%' identified by 'gomy55';

こうするとやっとエラーが出なくて、一般ユーザでログインできた。