学习笔记 - 线程间通信
一、线程间通信示例一
/**
* 线程间通讯: 其实就是多个线程在操作同一个资源 但是操作的动作不同
*
* 安全问题:
* 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();
}
}