Java 线程交互


线程交互

  • 线程的交互指线程之间需要一些协调通讯来共同完成任务;
  • 线程的交互可以通过 wait() 方法和 notify() 方法来实现;

1. Object() 方法

  • 调用 Object 类提供的 wait() 方法时,当前线程停止执行,并释放占有的资源,线程从运行状态转换为等待状态;
  • 必须从同步环境内调用 wait() notify() notifyAll() 方法,线程拥有对象的锁才能调用对象等待或通知方法;
  • 执行某个对象的 notify() 方法时,会唤醒对象等待池中的某个线程,使该线程从等待状态转换为就绪状态,执行某个对象的 notifyAll() 方法时,会唤醒对象等待池中的所有线程;
  • 多个线程在等待一个对象锁时要使用 notifyAll();
类型 方法 说明
void notify() 唤醒在此对象监听器上等待的单个线程
void notifyAll() 唤醒在此对象监听器上等待的所有线程
void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,当前线程等待
void wait(long timeout) 在其他线程调用此对象的 notify() 方法、 notifyAll() 方法、或未超过指定时间前,一个都不满足当前线程等待
void wait(long timeout,int nanos) 在其他线程调用此对象的 notify() 方法、 notifyAll() 方法前、或未超过指定时间、其他某个线程中断当前线程前,一个都不满足当前线程等待

2. 生产者-消费者问题

  • 生产者-消费者问题是线程交互的经典问题;
  • 生产者将生产的产品放到仓库中,而消费者从仓库取走产品;仓库一次存放固定数量的产品;如果仓库满了,生产者停止生产,等待消费者消费产品;如果仓库不满,生产者继续生产;如果仓库是空的,消费者停止消费,等仓库有产品再继续消费;
public class Test {
    public static void main(String[] args) {
        Stack s = new Stack(); //栈对象s
        Producer p = new Producer(s); //生产者对象
        Consumer c = new Consumer(s); //消费者对象
        new Thread(p).start(); //生产者线程1
        new Thread(p).start(); //生产者线程2
        new Thread(p).start(); //生产者线程3
        new Thread(c).start(); //消费者线程
    }
}

//Rabbit类(产品:玩具兔)
class Rabbit {
    int id; //玩具兔的id

    Rabbit(int id) {
        this.id = id;
    }

    public String toString() {
        return "玩具 : " + id; //重写toString()方法,打印玩具兔的id
    }
}

//栈(存放玩具兔的仓库)
class Stack {
    int index = 0;
    Rabbit[] rabbitArray = new Rabbit[6]; //存放玩具兔的数组

    public synchronized void push(Rabbit wt) { //玩具免放入数组栈的方法
        while (index == rabbitArray.length) {
            try {
                this.wait(); //栈满,等待消费者消费
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll(); //唤醒所有生产者进程
        rabbitArray[index] = wt; //将玩具放入栈
        index++;
    }

    public synchronized Rabbit pop() { //将玩具兔取走(消费)的方法
        while (index == 0) {
            try {
                this.wait(); //等待生产玩具兔
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll(); //栈不空,唤醒所有消费者线程
        index--; //消费
        return rabbitArray[index];
    }
}

//生产者类
class Producer implements Runnable {
    Stack st = null;

    Producer(Stack st) { //构造方法,为类的成员变量ss 赋值
        this.st = st;
    }

    public void run() { //线程体
        for (int i = 0; i < 20; i++) { //循环生产20 个玩具兔
            Rabbit r = new Rabbit(i); //创建玩具兔类
            st.push(r); //将生产的玩具兔放入栈
            //输出生产了玩具r,默认调用玩具兔类的toString()
            System.out.println("生产-" + r);
            try {
                Thread.sleep((int) (Math.random() * 200)); //生产一个玩具兔后睡眠
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//消费者类
class Consumer implements Runnable {
    Stack st = null;

    Consumer(Stack st) { //构造方法,为类的成员变量ss 赋值
        this.st = st;
    }

    public void run() {
        for (int i = 0; i < 20; i++) { //循环消费,即取走20 个玩具兔
            Rabbit r = st.pop(); //从栈中取走一个玩具兔
            System.out.println("消费-" + r);
            try {
                Thread.sleep((int) (Math.random() * 1000)); //消费一个玩具兔后睡眠
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/*
输出
生产-玩具 : 0
生产-玩具 : 0
生产-玩具 : 0
消费-玩具 : 0
生产-玩具 : 1
生产-玩具 : 1
生产-玩具 : 1
生产-玩具 : 2
消费-玩具 : 2
生产-玩具 : 2
生产-玩具 : 3
消费-玩具 : 2
生产-玩具 : 3
消费-玩具 : 3
消费-玩具 : 3
生产-玩具 : 4
消费-玩具 : 4
生产-玩具 : 4
消费-玩具 : 4
生产-玩具 : 2
消费-玩具 : 2
生产-玩具 : 5
消费-玩具 : 5
生产-玩具 : 5
消费-玩具 : 5
生产-玩具 : 6
消费-玩具 : 6
生产-玩具 : 6
消费-玩具 : 6
生产-玩具 : 7
消费-玩具 : 7
生产-玩具 : 7
消费-玩具 : 7
生产-玩具 : 8
消费-玩具 : 8
生产-玩具 : 8
消费-玩具 : 8
生产-玩具 : 9
消费-玩具 : 9
生产-玩具 : 9
消费-玩具 : 9
生产-玩具 : 10
消费-玩具 : 10
生产-玩具 : 10
消费-玩具 : 10
生产-玩具 : 11
 */

3. 多线程协作

public class Test {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        System.out.print(Thread.currentThread().getName());
        //启动计算线程
        b.start();
        //线程main拥有b对象上的锁
        synchronized (b) {
            try {
                System.out.println("等待对象b 完成计算……");
                //当前线程main 等待
                b.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("b 对象计算的总和是:" + b.total);
        }
    }
}

class ThreadB extends Thread {
    int total;

    public void run() {
        synchronized (this) {
            for (int i = 0; i < 101; i++) {
                total += i;
            }
            //计算完成了,唤醒在此对象监听器上等待的单个线程
            notify();
        }
    }
}
发布了185 篇原创文章 · 获赞 181 · 访问量 5351

猜你喜欢

转载自blog.csdn.net/Regino/article/details/104693567