Edited at

様々な言語における並行、並列処理(Java編)

More than 1 year has passed since last update.

前回と同じことをJavaでしてみよう。


long.java


public class Main {

private static final int REPEAT = 500000000;

private static long a = 0;

public static void main(String[] args) throws InterruptedException{

Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0;i <REPEAT; i++){
a = 1;
check();
}
}
});

Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0;i <REPEAT; i++){
a = -1;
check();
}
}
});

th1.start();
th2.start();

th1.join();
th2.join();

System.out.println("FINISHED!");
}

private static void check(){
if(a != 1 && a != -1){
System.out.println("LONG VALUE HAS BROKEN!");
}
}
}


排他制御ではないが、Javaで同様の問題を解決するにはvolatile修飾子がある

private volatile static long a = 0;

とすれば問題がなくなる。

volatileには「値の参照の際に、常に最新の値を見に行く」という性質があり、

ざっくり言えば、volatileの代入や参照はロックされているような振る舞いをする。

でもこれでは安全と言えないので、AtomicLongを使う。

アトミック: 不可分操作。ある操作を行なうときに他者がその操作に割り込めないことを指す。

private static AtomicLong a = new AtomicLong(0)


引用: http://d.hatena.ne.jp/cero-t/20120830/1346267076


Javaでの排他制御には、synchronizedブロックが使える。


synchronized

public class Main {

private static final int REPEAT = 500000000;

private static Long a = new Long(0);

public static void main(String[] args) throws InterruptedException{

Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0;i <REPEAT; i++){
synchronized (a){
a = new Long(1);
check();
}
}
}
});

Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0;i <REPEAT; i++){
synchronized (a) {
a = new Long(-1);
check();
}
}
}
});

th1.start();
th2.start();

th1.join();
th2.join();

System.out.println("FINISHED!");
}

private static void check(){
if(a != 1 && a != -1){
System.out.println("LONG VALUE HAS BROKEN!");
}
}
}


Javaで並列処理を行うには、Stream#parallelが使える。


parallel

public class Main {

public static void main(String[] args) {
// write your code here
IntStream.range(1,10).parallel().forEach(System.out::println);
}
}