JAvaスレッドセキュリティsynchronized同期ブロックと同期方法の応用
3917 ワード
package study_02;
public class unsafeThread{
public static void main(String[] args) {
Web12306 web12306 = new Web12306();
new Thread(web12306," A").start();
new Thread(web12306," B").start();
new Thread(web12306," C").start();
}
}
class Web12306 implements Runnable{
private int ticketNum = 10;
private boolean flag = true;
@Override
public void run() {
test();
}
public void test() {
while (flag) {
if (ticketNum <= 0) {
flag = false;
break;
}else {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "----->"+ ticketNum--);
}
}
}
}
実行後に検出されます
C----->9
A----->9
B----->10
A----->8
C----->8
B----->7
A----->6
B----->5
C----->6
A----->4
C----->3
B----->4
A----->2
C----->2
B----->2
C----->1
A----->-1
B----->0
2つの9が表示されます スレッドが安全でない場合-1も発生します
2つの9が出現したのは、各スレッドに独自のワークスペースがあるためであり、彼らはすべてホストと付き合い、ホストのticketNum=10、各スレッドはticketNum=10をそれぞれのワークスペースにコピーし、スレッドAがticketNumを10に取得した後、自分のワークスペースにコピーし、IO操作を行い、これがticketNumなのか10なのか、スレッドCがCPUに呼び出され、また、tickNumを10にコピーして自分のスペースにコピーすると、Aが呼び出され、tickNumの数値を修正してticketNUmを1から9に変更し、スレッドCの後も呼び出す、tickNumを1から9に変更する.
-1が現れるのは、チケットが1枚ある場合、スレッドCが呼び出されてもう1枚のチケットが見え、ticketNum=1を取得し、10 msのIO操作が行われるためである.このときticketNumはまだ修正されていないのか1なのか、このときスレッドBがIO操作を行っている場合、スレッドBも残りのチケットが1つあるのを見て、再びIO操作に入る.そしてスレッドBはticketNumに対して1つ減算ように呼び出され、同様のスレッドAである、最後に表示されるスレッドCは1スレッドBが0、スレッドAは-1である.
同期ロックをかける
package study_3;
/*
*
*
*
*
*/
public class synTest2{
public static void main(String[] args) {
synWeb12306 web12306 = new synWeb12306();
new Thread(web12306," A").start();
new Thread(web12306," B").start();
new Thread(web12306," C").start();
}
}
class synWeb12306 implements Runnable{
private int ticketNum = 10;
private boolean flag = true;
@Override
public void run() {
test();
}
public synchronized void test() {//
while (flag) {
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (ticketNum <= 0) {
flag = false;
break;
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "------>" +ticketNum--);
}
}
}
}
A------>10
A------>9
A------>8
A------>7
A------>6
A------>5
A------>4
A------>3
A------>2
A------>1
例2
package study_02;
import java.util.ArrayList;
import java.util.List;
public class unsafeThread4 {
public static void main(String[] args) throws InterruptedException {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(1000);//list
System.out.println(list.size());
}
}
結果は9998で、本来は10000であるべきです.これは同期ロック、同期ブロックです.
package study_02;
import java.util.ArrayList;
import java.util.List;
public class unsafeThread4 {
public static void main(String[] args) throws InterruptedException {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list) {//
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(1000);//list
System.out.println(list.size());
}
}