JavaA2Z

KAB-studio > プログラミング > JavaA2Z > synchronizedメソッドとは

synchronizedメソッド

日本語 同期関数
英語 synchronized method
ふりがな しんくろないずどめそっど
フリガナ シンクロナイズドメソッド

解説

同期を取るメソッド
synchronizedで修飾されたメソッド。「synchronized 戻り値 メソッド(引数){ 実装 }」のように、メソッド宣言の先頭にsynchronizedが付けられたメソッド
 
マルチスレッドにおいて、複数のスレッドが同時に呼び出すことができないメソッド
synchronizedメソッドは、呼び出すスレッドを1つに限定することができる。2つのスレッドからほぼ同時に呼び出された場合、先に呼び出した側がメソッドを終了させない限り、後から呼び出した側が待たされる。
 
ただし、synchronizedメソッドは、そのメソッドが属するインスタンスが異なる場合には機能しない。つまりsynchronizedメソッドは、thisが同じ場合にのみ待たせることができ、thisが異なる場合には待たせない。
これは、synchronizedメソッドが「フィールド同期を取る」ためのものだからである。複数のスレッドが同時にアクセスすると、先のスレッドフィールドの値を書き換える前に後のスレッドフィールドの値を読み取り、値が誤ったものになってしまう可能性があるからである。
synchronizedメソッドはそれを防ぐためのものである。フィールドにアクセスするメソッドをsynchronizedメソッドとすることで、先のスレッドメソッド呼び出し終えるまで後のスレッドを待たせることができる。それにより、フィールドの値を常に保つことができる。
インスタンスが異なれば、フィールドも異なるため、同期を取る必要はない。インスタンスが異なるとsynchronizedメソッドが機能しないのはこのためである。
 
また、この目的のため、synchronizedメソッドは全て同期の対象となる。
synchronizedメソッドが複数存在する場合、同じように機能する。synchronizedメソッドAがスレッド1に呼び出されている間に、synchronizedメソッドBをスレッド2呼び出そうとした場合、呼び出しスレッド1によるsynchronizedメソッドA呼び出しが終了するまで待たされる。
 
synchronizedメソッドを使用することで同期を取ることができるが、待ち時間が生じるため、動作に時間が掛かる可能性がある。
 
synchronizedメソッド以外にも、同期を取る機能としてsynchronizedブロックがある。
synchronizedメソッドは、synchronizedブロックthisに対してうものであり、自クラスフィールドに対して排他制御をいたい場合にはsynchronizedメソッドの方がいいだろう。

参考サイト


(KAB-studioからのおしらせです)

サンプルプログラム(とか)サンプルを別ウィンドウで表示サンプルをクリップボードへコピー(WindowsでIEの場合のみ)

// Sample.java
public class Sample
{
    public static void main( String[] args )
    {
        try
        {
            SynchronizeClass synchronizeClass = new SynchronizeClass();
            
            // 別スレッドの方を呼び出します。
            OtherThread thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // synchronizedメソッドを呼び出します。
            synchronizeClass.synchronizedMethod( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド終了 from OtherThread
            // synchronizedMethod()メソッド開始 from Sample
            // OtherThread終了
            // synchronizedMethod()メソッド終了 from Sample
            // Sample終了

            // このように、synchronizedメソッドは、一度に1つの
            // スレッドしか呼び出せません。先に呼び出した方が
            // 終了するまで待ちます。

            // synchronizedメソッドの排他処理は、インスタンスに
            // 対して行われます。そのため、同じsynchronizedメソッドでも、
            // インスタンス(synchronizedメソッドにとってはthis)が
            // 異なれば排他されません。

            thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // synchronizedメソッドを呼び出します。ただし、
            // 別のインスタンスを作ってそちらのメソッドを
            // 呼び出します。
            SynchronizeClass synchronizeClass2 = new SynchronizeClass();
            synchronizeClass2.synchronizedMethod( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド開始 from Sample
            // synchronizedMethod()メソッド終了 from OtherThread
            // OtherThread終了
            // synchronizedMethod()メソッド終了 from Sample
            // Sample終了

            // このように、インスタンスが異なれば排他されません。

            // インスタンスが同じであれば異なるsynchronizedメソッドでも
            // 排他されます。

            thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // もうひとつのsynchronizedメソッドを呼び出します。
            synchronizeClass.synchronizedMethod2( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド終了 from OtherThread
            // synchronizedMethod2()メソッド開始 from Sample
            // OtherThread終了
            // synchronizedMethod2()メソッド終了 from Sample
            // Sample終了

            // このように、synchronizedMethod()メソッドが
            // 終わるまで、synchronizedMethod2()メソッドが
            // 呼べなくなっています。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }
}

/**
*   別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
    /** SynchronizeClassクラス。 */
    private SynchronizeClass synchronizeClass;

    /** コンストラクタ。 */
    public OtherThread( SynchronizeClass synchronizeClass )
    {
        this.synchronizeClass = synchronizeClass;
    }
    
    /**
    *   Threadクラスのrun()メソッドを
    *   オーバーライドしたメソッド。このメソッドが
    *   別スレッドとして呼び出されます。
    */
    public void run()
    {
        System.out.println( "OtherThread開始" );
        // synchronizedメソッドを呼び出します。
        // このインスタンスは、Sampleクラスのmain()メソッドで
        // 作られたものです。
        synchronizeClass.synchronizedMethod( "OtherThread" );
        System.out.println( "OtherThread終了" );
    }
}

/**
*   同期処理テスト用クラス。
*/
class SynchronizeClass
{
    /** フィールド。 */
    private int data = 0;
    
    /**
    *   synchronizedメソッド。
    */
    public synchronized void synchronizedMethod( String name )
    {
        try
        {
            System.out.println( "synchronizedMethod()メソッド開始 from " + name );
            // 5秒待ちます。
            Thread.sleep( 5 * 1000 );
            System.out.println( "synchronizedMethod()メソッド終了 from " + name );

            // たとえば、dataフィールドにアクセスする場合。
            data = 100;
            // synchronizedによる同期は、この「フィールドへのアクセス」を
            // 1スレッドに限定するためのものです。だから、
            // このメソッドにとってのインスタンス(つまりthis)が
            // 異なる場合には同期が取られないのです。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }

    /**
    *   もうひとつのsynchronizedメソッド。
    */
    public synchronized void synchronizedMethod2( String name )
    {
        try
        {
            System.out.println( "synchronizedMethod2()メソッド開始 from " + name );
            // 5秒待ちます。
            Thread.sleep( 5 * 1000 );
            System.out.println( "synchronizedMethod2()メソッド終了 from " + name );

            // たとえば、dataフィールドにアクセスする場合。
            data = 100;
            // synchronizedによる同期は、この「フィールドへのアクセス」を
            // 1スレッドに限定するためのものです。だから、
            // フィールドに対してアクセスする複数のメソッドを
            // 同時に排他できるようになっているのです。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }
}
// Sample.java
public class Sample
{
    public static void main( String[] args )
    {
        try
        {
            SynchronizeClass synchronizeClass = new SynchronizeClass();
            
            // 別スレッドの方を呼び出します。
            OtherThread thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // synchronizedメソッドを呼び出します。
            synchronizeClass.synchronizedMethod( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド終了 from OtherThread
            // synchronizedMethod()メソッド開始 from Sample
            // OtherThread終了
            // synchronizedMethod()メソッド終了 from Sample
            // Sample終了

            // このように、synchronizedメソッドは、一度に1つの
            // スレッドしか呼び出せません。先に呼び出した方が
            // 終了するまで待ちます。

            // synchronizedメソッドの排他処理は、インスタンスに
            // 対して行われます。そのため、同じsynchronizedメソッドでも、
            // インスタンス(synchronizedメソッドにとってはthis)が
            // 異なれば排他されません。

            thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // synchronizedメソッドを呼び出します。ただし、
            // 別のインスタンスを作ってそちらのメソッドを
            // 呼び出します。
            SynchronizeClass synchronizeClass2 = new SynchronizeClass();
            synchronizeClass2.synchronizedMethod( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド開始 from Sample
            // synchronizedMethod()メソッド終了 from OtherThread
            // OtherThread終了
            // synchronizedMethod()メソッド終了 from Sample
            // Sample終了

            // このように、インスタンスが異なれば排他されません。

            // インスタンスが同じであれば異なるsynchronizedメソッドでも
            // 排他されます。

            thread = new OtherThread( synchronizeClass );
            thread.start();

            // 2秒待ちます。OtherThreadの方を先に
            // 実行するためです。
            Thread.sleep( 2 * 1000 );

            // こちらでも。
            System.out.println( "Sample開始" );
            // もうひとつのsynchronizedメソッドを呼び出します。
            synchronizeClass.synchronizedMethod2( "Sample" );
            System.out.println( "Sample終了" );
            // OtherThread開始
            // synchronizedMethod()メソッド開始 from OtherThread
            // Sample開始
            // synchronizedMethod()メソッド終了 from OtherThread
            // synchronizedMethod2()メソッド開始 from Sample
            // OtherThread終了
            // synchronizedMethod2()メソッド終了 from Sample
            // Sample終了

            // このように、synchronizedMethod()メソッドが
            // 終わるまで、synchronizedMethod2()メソッドが
            // 呼べなくなっています。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }
}

/**
*   別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
    /** SynchronizeClassクラス。 */
    private SynchronizeClass synchronizeClass;

    /** コンストラクタ。 */
    public OtherThread( SynchronizeClass synchronizeClass )
    {
        this.synchronizeClass = synchronizeClass;
    }
    
    /**
    *   Threadクラスのrun()メソッドを
    *   オーバーライドしたメソッド。このメソッドが
    *   別スレッドとして呼び出されます。
    */
    public void run()
    {
        System.out.println( "OtherThread開始" );
        // synchronizedメソッドを呼び出します。
        // このインスタンスは、Sampleクラスのmain()メソッドで
        // 作られたものです。
        synchronizeClass.synchronizedMethod( "OtherThread" );
        System.out.println( "OtherThread終了" );
    }
}

/**
*   同期処理テスト用クラス。
*/
class SynchronizeClass
{
    /** フィールド。 */
    private int data = 0;
    
    /**
    *   synchronizedメソッド。
    */
    public synchronized void synchronizedMethod( String name )
    {
        try
        {
            System.out.println( "synchronizedMethod()メソッド開始 from " + name );
            // 5秒待ちます。
            Thread.sleep( 5 * 1000 );
            System.out.println( "synchronizedMethod()メソッド終了 from " + name );

            // たとえば、dataフィールドにアクセスする場合。
            data = 100;
            // synchronizedによる同期は、この「フィールドへのアクセス」を
            // 1スレッドに限定するためのものです。だから、
            // このメソッドにとってのインスタンス(つまりthis)が
            // 異なる場合には同期が取られないのです。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }

    /**
    *   もうひとつのsynchronizedメソッド。
    */
    public synchronized void synchronizedMethod2( String name )
    {
        try
        {
            System.out.println( "synchronizedMethod2()メソッド開始 from " + name );
            // 5秒待ちます。
            Thread.sleep( 5 * 1000 );
            System.out.println( "synchronizedMethod2()メソッド終了 from " + name );

            // たとえば、dataフィールドにアクセスする場合。
            data = 100;
            // synchronizedによる同期は、この「フィールドへのアクセス」を
            // 1スレッドに限定するためのものです。だから、
            // フィールドに対してアクセスする複数のメソッドを
            // 同時に排他できるようになっているのです。
        }
        catch( InterruptedException e )
        {
            // sleep()メソッドが途中で中断されると
            // InterruptedException例外が投げられます。
            // 滅多にないですが。
            e.printStackTrace();
        }
    }
}

この単語を含むページ

「みだし」に含まれているページ

「サンプルプログラムとか」に含まれているページ

はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
Yahoo!ブックマーク 詳細を表示 users
del.icio.us 登録する RSSに登録
サンプルを別ウィンドウで表示
サンプルをクリップボードへコピー(WindowsでIEの場合のみ)
update:2005/10/13
このページは、Javaプログラミング言語についての用語を網羅した辞書「JavaA2Z」の一ページです。
詳しくは「JavaA2Z」表紙の説明をご覧ください。