【Java】synchronizedとは?

Java

Javaにはsynchronizedというキーワードが存在します。

これを使用することで競合という現象を抑制することができます。

この記事では、

「そもそも競合って何なの?」

「synchronizedを使用する方法について知りたい」

「synchronizedを使用する上での注意点をしりたい」

といった疑問点について解説していきたいと思います。

競合とは?

ではまず初めに、そもそも競合とは何なのかについて解説していきます。

読んで字のごとくかもしれませんが、競合とはあるスレッドが一つの変数値の変更を実施しようとしている間に、他のスレッドがその変数値を先に変更してしますことで発生する事象です。

例えば処理Aが変数a=3に100を掛けて値を変更しようとしていたとします。

処理Aが変数aを読み込んで、変更を加えようとしている間に処理Bが変数a=3に200を掛けて値の変更をしてしまったとします。

そうすると処理Aが読み込んだ変数aの元の値と異なる値が誕生します。

こういった問題が発生しないようにするために、synchronizedキーワードを使用して、あるスレッドが処理をしている間に、他のスレッドが処理を実施できないようにロックします。

このように思ってもいない動作が起こらないようにする方法を排他制御と言います。

因みにスレッドについて分からないという方は下記の記事で解説していますので、一度読んでみてください。

【Java】並列処理について | エンジニアKISARAGIの備忘録 (kisaragi-it.com)

では次にsynchronizedの使用方法についてですが、メソッドに使用する方法とメソッド内部の一部に使用する方法の2パターンがあります。

まずメソッドに使用する方法ですが、下記のように戻り値(下記ですとvoid)の前に入力することで使用可能です。

【使用例】
public synchronized void メソッド名(){
	何らかの処理1
	何らかの処理2
	何らかの処理3
}

しかしこの使用方法ですとメソッド全体にsynchronizedが反映されてしまい、そのメソッド全体が待機させられてしまいます。

なので本当に待機が必要な処理のみに反映させたい場合はメソッド内の一部にsynchronizedを使用する必要があります。

そういった場合は下記のようにsynchronizedブロックを使用します。

【使用例】
public void メソッド名(){
	何らかの処理1
	synchronized(競合させたくない変数){
		何らかの処理2
	}
	何らかの処理3
}

これにより一部にsynchronizedを反映することが可能となります。

デッドロックについて

ここまでsynchronizedについて解説してきましたが、競合をさせないために実施したsynchronizedには注意すべき点があります。

それがデッドロックという現象です。

これはどういったものかというと、例えばとあるソフトに機能AとBがあったとします。

そして機能Aは処理aをまず実施し、機能Bの方は処理bを実施中で、ともに排他制御をしています。

しかしその後機能Aは処理aの排他制御は維持した状態で処理bを実施しようとします。

しかし処理bは機能Bが排他制御した状態ですので、機能Bが処理bの排他制御を終了させるまで機能Aは待ちます。

そうしているうちに機能Bは処理aを実施しようとします。

しかし処理aは機能Aにより排他制御されていて、実施することができません。

そこで機能Bは処理aの排他制御が解除されるまで待ちます。

これを図にすると下記のようになり、互いに排他制御しあって待ち状態となり処理が止まってしまいます。

この状態をデッドロックと言います。

自分も仕事で他のプログラムを触っていますが、たまにこの事象が発生してソフト自体が動かなくなるということはありました。

ではそんなデッドロックを防ぐ方法はあるのかと言いますと、簡単な方法があります。

それが実施する処理の順番を統一するというものです。

先ほどの例ですと、機能Aは処理a→処理b、機能Bは処理b→処理aと順番が異なりましたが、これをどちらの機能も処理a→処理bや処理b→処理aのように統一することでデッドロックは発生しなくなります。

自分でプログラムを組んだりしていてデッドロックが発生してしまった時のために覚えておくことをオススメします。

まとめ

この記事ではsynchronizedキーワードについて解説してきました。

  • 競合とは?
  • デッドロックについて

synchronizedは使用することで競合の発生を阻止することができます。

しかしsynchronizedを使用したことで今度はデッドロックが発生してしまうこともありますので、その点は注意が必要です。

競合やデッドロックは不具合の元ですので、ぜひ今回紹介したことを覚えておいて損はないはずです。

以上で今回の解説は終了です。

コメント

タイトルとURLをコピーしました