學習筆記 - 線程間通信
一、線程間通信示例一
/**
* 線程間通訊: 其實就是多個線程在操作同一個資源 但是操作的動作不同
*
* 安全問題:
* 1.同步裏面必須有兩個線程
* 2.必須用同一個鎖
*
* @author Administrator
*
*/
/**
* wait:
* notify()
* notifyAll();
*
* 都使用在同步中,因爲要對持有監視器(鎖)的線程操作
* 所以要使用在同步中,因爲只有同步才具有鎖。
*
* 爲什麼這些操作線程的方法要定義Object類中?
* 因爲這些方法在操作同步中線程時,都必須要表示他們所操作線程只有的鎖。
* 只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒
* 不可以對不同鎖中的線程進行喚醒。
*
* 也就是說,等待和喚醒必須是同一個鎖。
* 而鎖可以是任意對象,所以可以被任意調用的方法定義在Object中。
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Input implements Runnable {
private Res r;
// Object obj = new Object();
Input(Res r) {
this.r = r;
}
@Override
public void run() {
int x = 0;
while (true) {
//能夠成功輸出的方法:使用單一的字節碼 : Input.class Output.class Res.class r
//使用 Object obj = new Object() 不行,原因:不是同一份字節碼
//this 也不行,this 是指當前類的字節碼,所以也是錯誤的
synchronized (r) {
//flag爲false,不執行wait()
//第二次,爲true,執行賦值操作
if(r.flag)
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (x == 0) {
r.name = "mike";
r.sex = "man";
} else {
r.name = "lise";
r.sex = "woman";
}
x = (x + 1) % 2;
//flag 變爲true 同時喚醒下面的線程
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable {
private Res r;
//Object obj = new Object();
Output(Res r) {
this.r = r;
}
@Override
public void run() {
while (true) {
synchronized (r) {
//爲fasle 等待
//同樣第二次爲true,執行打印操作
if(!r.flag)
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(r.name + "........" + r.sex);
//爲true喚醒上面的線程
r.flag = true;
r.notify();
}
}
}
}
class Res {
String name;
String sex;
boolean flag = false;
}
二、線程間通信示例二
/**
* 線程間通訊: 其實就是多個線程在操作同一個資源 但是操作的動作不同
*
* 安全問題:
* 1.同步裏面必須有兩個線程
* 2.必須用同一個鎖
*
* @author Administrator
*
*/
/**
* wait: notify() notifyAll();
*
* 都使用在同步中,因爲要對持有監視器(鎖)的線程操作 所以要使用在同步中,因爲只有同步才具有鎖。
*
* 爲什麼這些操作線程的方法要定義Object類中? 因爲這些方法在操作同步中線程時,都必須要表示他們所操作線程只有的鎖。
* 只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒 不可以對不同鎖中的線程進行喚醒。
*
* 也就是說,等待和喚醒必須是同一個鎖。 而鎖可以是任意對象,所以可以被任意調用的方法定義在Object中。
public class InputOutputDemo2 {
public static void main(String[] args) {
Res2 r = new Res2();
Input2 in = new Input2(r);
Output2 out = new Output2(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Input2 implements Runnable {
private Res2 r;
// Object obj = new Object();
Input2(Res2 r) {
this.r = r;
}
@Override
public void run() {
int x = 0;
while (true) {
// 能夠成功輸出的方法:使用單一的字節碼 : Input.class Output.class Res.class r
// 使用 Object obj = new Object() 不行,原因:不是同一份字節碼
// this 也不行,this 是指當前類的字節碼,所以也是錯誤的
synchronized (r) {
// flag爲false,不執行wait()
// 第二次,爲true,執行賦值操作
if (x == 0)
r.set("111111", "man");
else
r.set("wang", "woman");
x = (x + 1) % 2;
}
}
}
}
class Output2 implements Runnable {
private Res2 r;
// Object obj = new Object();
Output2(Res2 r) {
this.r = r;
}
@Override
public void run() {
while (true) {
synchronized (r) {
r.out();
}
}
}
}
class Res2 {
private String name;
private String sex;
boolean flag = false;
public synchronized void set(String name, String sex) {
if (flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = true;
notify();
}
public synchronized void out() {
if (!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("name" + "......." + name + "--" + "sex"
+ "........." + sex);
flag = false;
notify();
}
}