Java 线程交互


线程交互

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

1. Object() 方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值