1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

java何でもメモ2

1
Last updated at Posted at 2018-05-30

自分の勉強用のメモ。

メモリ領域

変数の値、生成されたインスタンス、呼び出されたメソッドの履歴などを格納する領域。
これらをどこに格納するかは、JVMによって管理している。
メモリ領域には2種類あり

  • スタック
  • ヒープ

がある。

スタック

メソッドの呼び出し履歴、メソッド内で宣言された変数(ローカル変数)の値。
メソッドの処理が終わると、その情報はスタックから削除される。

ヒープ

クラスから生成されたインスタンス。
インスタンスが、どの変数からも参照されなくなったとき(参照先の変更、nullの代入)
に、JVMのガーベッジコレクションで自動で開放される。

スレッド

以下の2種類がある。

  • シングルスレッド
  • マルチスレッド

マルチスレッドを作成する

方法は2つ

  • Threadクラスを継承した新しいクラスを作る
  • Runnableインターフェースを実装した新しいクラスを作る。

Threadクラスで作る

Threadクラスを継承したクラスのインスタンスを生成して、
そのインスタンスのstartメソッドを呼ぶ。

実行するのは、startメソッドだけど、
Threadクラスを継承したサブクラスでは、
Threadクラスが持つrunメソッドをオーバライドする。

startメソッドを経由して、runメソッドが実行される。
結果は必ず同じではなく、実行されるたびに変わる(変わらない時もある)

class MyTread extends Thread{
    //メモ:スーパークラスで定義されているアクセス修飾子より、レベルを下げることはできない
    //Thread から継承されたメソッドの可視性を下げることはできません
    public void run() {
        for(int i = 0; i < 5; i++) {
            System.out.println("MyTread.run:"+i);
        }
    }
}

public class SampleProgram{
    public static void main(String[] args) {
        MyTread mt = new MyTread();
        mt.start();

        for(int i = 0; i < 5; i++) {
            System.out.println("main:"+i);
        }
    }
}

//結果
main:0
main:1
main:2
MyTread.run:0
MyTread.run:1
MyTread.run:2
MyTread.run:3
main:3
MyTread.run:4
main:4

Runnableインタフェースで作る

継承して作った時とあんまり変わらない。

class MyTread implements Runnable{
    public void run() {
        for(int i = 0; i < 5; i++) {
            System.out.println("MyTread.run:"+i);
        }
    }
}

public class SampleProgram{
    public static void main(String[] args) {
        MyTread mt = new MyTread();
        Thread t = new Thread(mt);
        t.start();

        for(int i = 0; i < 5; i++) {
            System.out.println("main:"+i);
        }
    }
}

Thread.sleep(ミリ秒(=1000分の1秒))

スレッドの処理を一定時間止める。
単位は、ミリ秒。
1000:1秒
2000:2秒

マイクロ秒だと
1000000:1秒

Thread.sleepメソッドは、InterruptedException型の例外を投げる可能性があるので
catchしないといけない。

public class SampleProgram{
    public static void main(String[] args) {

        for(int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main:"+i);
        }
    }
}

// Runnableインターフェースを実装したほうで試してみた
class MyTread implements Runnable {
    public void run() {
        for(int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
            System.out.println("MyTread.run:"+i);
        }
    }
}

public class SampleProgram{
    public static void main(String[] args) {
        MyTread mt = new MyTread();
        Thread t = new Thread(mt);
        t.start();

        for(int i = 0; i < 5; i++) {
            System.out.println("main:"+i);
        }
    }
}

join()

スレッドの処理を待つことができる。

joinメソッドは、InterruptedException型の例外を投げる可能性があるので
catchしないといけない。

MyTreadクラスの処理がすべて終わってから、mainの処理が実行されている。

class MyTread implements Runnable {
    public void run() {
        for(int i = 0; i < 5; i++) {
            System.out.println("MyTread.run:"+i);
        }
    }
}

public class SampleProgram{
    //今度は、throwsしてみる。
    public static void main(String[] args) throws InterruptedException {
        MyTread mt = new MyTread();
        Thread t = new Thread(mt);
        t.start();

        t.join();
        for(int i = 0; i < 5; i++) {
            System.out.println("main:"+i);
        }
    }
}

スレッドを止める

runメソッドの処理を終了させれば、そのスレッドの処理は終了する。
うーん、、、、今は置いておこう。

同期をとる。

マルチスレッドで動く場合、複数のスレッドで同じ変数の値を共有すると
不整合が生じることがある。

以下は、合計金額が1000000円になる予定のプログラム

class Bank{
    static int money = 0;
    static void addOneYen() {
        money++;
    }
}
class Customer extends Thread{
    public void run() {
        for(int i = 0; i < 10000; i++) {
            Bank.addOneYen();
        }
    }
}
public class MultiThreadEx {
    public static void main(String[] args) {
        Customer[] customers = new Customer[100];
        for(int i = 0; i < 100; i++) {
            customers[i] = new Customer();
            customers[i].start();
        }

        for(int i = 0; i < 100; i++) {
            try {
                customers[i].join();
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Bank.money["+Bank.money+"]");
    }
}

//結果
Bank.money[628887]

現在の金額を参照・更新するタイミングで、各スレット間で整合性がとれないため、
合計金額がおかしくなる。
そんな時は、addOneYenメソッドの前に「synchronized」を付ける。

    static synchronized void addOneYen() {
        money++;
    }

synchronizedをメソッドの前につけると、1度に1つのスレッドしか実行できない。
あるスレットが処理を行っているときは、ほかのスレットは自分の番まで待機する。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?