今天学习了等待唤醒机制,通过一个例子做个小小的总结。
需求是对某个数据进行修改和输出操作,要求两个操作同时进行,且先修改后输出。
设计思路:1,需要一个公共数据类。两个线程,一个Input、一个Output。
2,Input和Output应该是两个线程,这样才能同时进行。
3,Input和Output的对数据进行修改的方法应该实现同步,以解决线程安全问题。
4,需要有等待唤醒机制,这样才能实现先修改后输出。
实现代码:
//共享资源类,name和sex是被修改的数据,flag作为数据被修改之后的标识。/*Input作为对数据进行写的线程。Output作为读线程。首先应该对操作共享数据的代码进行同步,锁必须和读线程使用的是同一把锁,在这个程序中,
* 唯一的对象是共有数据对象,可以将它作为锁。同步机制,将某个对象锁住,只有拿到该锁的线程可以对共享数据进行操作,其他线程没办法进入同步
* 代码中,但是一旦线程释放了该锁,那么所有的线程都可以抢这个锁,没有先后顺序,刚刚使用了锁的线程又会重新加入抢锁阵营,难免会出现一个线
* 程连续多次对共享数据进行更改,就没法保证线程的先后顺序。为了使线程有秩序的先这个后那个,就需要在这个对共享数据操作完之后等一等,不要
* 立马去抢锁,这样就可以轮到没有持有锁的线程使用锁,因此需要等待唤醒机制。但是wait()、notify()、notifyAll()方法是Object
* 类中的方法,只有锁对象可以调用,且wait()和notify()或者wait()和notifyAll()方法的调用者必须是同一个对象,使用同一把锁。
* 且wait()方法会抛出异常,但是由于Runnable接口中的run方法没有抛出异常,所以即使wait()需要抛出异常,也不能抛出,只能通过
* try-catch处理。
*/
class Res{
String name;
String sex;
boolean flag=false;
}
class Input implements Runnable{
private Res r;
Input(Res r){
this.r=r;
}
public void run(){
int x=0;
while(true){
synchronized(r){
if(r.flag){//如果数据被修改过,那么写线程wait(),等待读线程完成后唤醒。
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="丽丽";
r.sex="女";
}
r.flag=true;//完成写操作后,将标志位改为true,表示写线程完成,唤醒其他线程。
r.notify();
}
x=(x+1)%2;
}
}
}
class Output implements Runnable{
private Res r;
Output(Res r){
this.r=r;
}
public void run(){
while(true){
synchronized(r){
if(!r.flag){//如果标志位为false,说明读线程完成,必须等待写线程操作。
try{
r.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println(r.name+"::"+r.sex);
r.flag=false;//读完之后将标志位改为false,表示读完,并唤醒写线程。
r.notify();
}
}
}
}
public class ThreadComm {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Res r=new Res();
Input in=new Input(r);
Output ou=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(ou);
t1.start();
t2.start();
}
}
/*代码优化:
* 将共有资源类的成员变量私有化,并且提供对外公共方法,在公共资源类中就进行同步,简化线程类。
* */
class Res2{
private String name;
private String sex;
boolean flag=false;
public synchronized void set(String name,String sex){
if(flag){
try{
this.wait();
}catch(Exception e){
e.printStackTrace();
}
}
this.name=name;
this.sex=sex;
flag=true;
this.notify();
}
public synchronized void get(){
if(!flag){
try{
this.wait();
}catch(Exception e){
e.printStackTrace();
}
}
System.out.println(name+"::"+sex);
flag=false;
this.notify();
}
}
class Input2 implements Runnable{
private Res2 r;
Input2(Res2 r){
this.r=r;
}
public void run(){
int x=0;
while(true){
if(x==0){
r.set("Mick", "Man");
}else{
r.set("丽丽", "女女女女");
}
x=(x+1)%2;
}
}
}
class Output2 implements Runnable{
private Res2 r;
Output2(Res2 r){
this.r=r;
}
public void run(){
while(true){
r.get();
}
}
}
public class WaNoYouDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Res2 r=new Res2();
new Thread(new Input2(r)).start();
new Thread(new Output2(r)).start();
}
}