栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java并发编程-线程协作方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java并发编程-线程协作方式

1、object - wait、notify、notifyAll

wait、notify、notifyAll是object中的方法,final修饰,因此不能被重写。

public final native void notify();

public final native void notifyAll();

public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait() throws InterruptedException {
        wait(0);
}

wait、notify、notifyAll三个方法调用的前提是已经获取到当前实例对象锁,也就是在synchroized作用范围下。

1.1、wait

1、wait的作用是让当前获取了对象锁的线程释放对象锁,并进入阻塞状态,除非发生下列四种中的某一种情况,否则线程会一直在处于阻塞状态。
(1)有其他线程调用了object的notify方法来唤醒线程;
(2)有其他线程调用了object的notifyAll方法来唤醒线程;
(3)有其他线程调用了被阻塞线程thread的interrupt方法来唤醒被阻塞线程。
(4)wait方法超时,该线程继续运行。

线程被重新唤醒后,wait后面的代码不会继续执行,线程会重新获取对象锁进入synchronized代码块。

2、如果当前线程没有持有对象锁的情况下,调用了object的wait,会抛出IllegalMonitorStateException异常。

3、当前线程调用object的wait后,如果被中断的话,InterruptedException会抛出。

1.2、notify

notify的作用是唤醒一个等待object对象锁的线程,待当前线程退出synchronized代码块释放对象锁后,被唤醒的线程才能获得对象锁。如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

如果当前线程并没有持有object的对象锁,但调用了object的notify,会抛出IllegalMonitorStateException异常。

1.3、notifyAll

notifyAll的作用是唤醒所有正在等待对象锁的线程,待当前线程退出synchronized代码块释放对象锁后,被唤醒的线程才能获得对象锁。如果当前线程并没有持有object的对象锁,但调用了object的notify,会抛出IllegalMonitorStateException异常。

1.4、生产者、消费者模型

使用wait、notify实现:

public class Test {
    private int queueSize = 10;
    private PriorityQueue queue = new PriorityQueue(queueSize);
      
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();          //每次移走队首元素
                    queue.notify();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    queue.notify();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                }
            }
        }
    }
}
2、condition - await、signal、signalAll

wait、signal、signalAll是Condition中的方法,Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition() ,调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用。

Conditon中的await()对应Object的wait();

Condition中的signal()对应Object的notify();

Condition中的signalAll()对应Object的notifyAll()。

使用condition实现生产者、消费者模型:

public class Test {
    private int queueSize = 10;
    private PriorityQueue queue = new PriorityQueue(queueSize);
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
     
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            notEmpty.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.poll();                //每次移走队首元素
                    notFull.signal();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                } finally{
                    lock.unlock();
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    notEmpty.signal();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                } finally{
                    lock.unlock();
                }
            }
        }
    }
}
3、object和condition两种线程协作方式比较

        object的协作方式,因为只锁定一个object对象,因此只能有一个等待队列,在实际应用时可能需要多个,比如读和写。为了这个灵活性,lock将同步控制和等待队列分离开来,lock对象负责同步控制,保证在某个时刻只有一个线程访问临界区。等待队列中存储着被阻塞的线程,每个condition对应一个等待队列,而一个lock可以创建多个condition。

举例说明如下:

线程A:

synchronized(obj){

    obj.wait(); 
    doSomething();

}

线程C:

synchronized(obj){

    obj.wait(); 

    doSomething();

}

线程B:

synchronized(obj){

    obj.notify(); 

}

假设三个线程执行顺序,线程A-->线程C-->线程B

所以问题来了:等待的线程中有A和C, B notify后只会唤醒其中一个执行,假如我们的需求是想让A线程执行,那么这种object的方式是无法控制的。用一个lock和两个condition就可以解决。

ReentrantLock lock = new ReentrantLock(true);

Condition aCondition = reentrantLock.newCondition();

Condition cCondition = reentrantLock.newCondition();

线程A:

{

lock.lock();

aCondition.await(); 
aCondition.signal();
doSomething();
lock.unlock();

}

线程C:

{

lock.lock();

cCondition.await();

doSomething();

lock.unlock();

}

线程B:

{

lock.lock();

aCondition.signal(); 

//cCondition.signal();

lock.unlock();

}

可见condition比object更灵活。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/847084.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号