zoukankan      html  css  js  c++  java
  • synchronized与条件同步

    在并发编程中,有这样的需求:当满足某个条件时线程执行同步块中的代码,条件不满足时,让线程在此等待,直至条件满足再执行同步代码块。

    java的Object类即提供了一类这样的方法wait(),notifyAll()/notify(),调用wait()方法后,线程A释放对同步代码块的控制并进入休眠状态,

    在条件再次满足时,调用notifyAll()/notify()方法唤醒线程A,线程A将被唤醒并重新试图获得同步代码块的控制,在进入同步代码块成功之后,

    再次对条件判断。

    典型的应用场景是生产者-消费者模式,有一个固定大小的缓冲区存放消息,一个或者多个生产者线程把消息写入缓冲区;一个或者多个消费者从缓冲区获取消息。

    如果缓冲区满了,生产者就不能写入消息,并等待。如果缓冲区为空,消费者就不能获取消息,并等待。

    我们使用synchronized关键字来同步代码块,由于java中的类都继承自Object类,因此可以在我们的类中调用wait()让线程进入休眠并等待唤醒。

    首先创建一个类MessageStorage来管理消息缓冲区,并使用LinkedList队列来作为消息缓冲区:

    public class MessageStorage {
        private int maxSize;
        private List<String> messages;
    
        public MessageStorage(int maxSize) {
            this.maxSize = maxSize;
            messages = new LinkedList<String>();
        }
        public void set(String message){
            synchronized (this){
                while(messages.size() == maxSize){
                    try {
                        System.out.print("the message buffer is full now,startinto wait()
    ");
                        wait();//满足条件时,线程休眠并释放锁。当调用notifyAll()时。线程唤醒并重新获得锁
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                try{
                 Thread.sleep(100);
                }catch (InterruptedExceptione){
                    e.printStackTrace();
                }
                messages.add(message);
                System.out.print("add message:"+message+" success
    ");
                notifyAll();//唤醒休眠的线程
            }
        }
        public String get(){
            String message = null;
            synchronized (this){
                while(messages.size() == 0){
                    try {
                        System.out.print("the message buffer is empty now,startinto wait()
    ");
                        wait();
                    }catch (InterruptedExceptione){
                        e.printStackTrace();
                    }
                }
                try{
                    Thread.sleep(100);
                }catch (InterruptedExceptione){
                    e.printStackTrace();
                }
                message =((LinkedList<String>)messages).poll();
                System.out.print("get message:"+message+" success
    ");
                notifyAll();
            }
            return message;
        }
    }


    实现一个生产者,向消息缓冲区写入消息:

    public class Producer implements Runnable{
        private MessageStorage messageStorage;
        private int index;
        public Producer(MessageStorage messageStorage,int index) {
            this.messageStorage = messageStorage;
            this.index = index;
        }
    
        public void run(){
            for(int i=0; i<5; i++){
                StringBuffer message = new StringBuffer("thread id:");
                message.append(index);
                message.append(" id:");
                message.append(i);
                messageStorage.set(message.toString());
            }
        }
    }


    实现一个消费者,从消息缓冲区取数据:

    public class Consumer implements Runnable{
        private MessageStorage messageStorage;
        public Consumer(MessageStorage messageStorage) {
            this.messageStorage = messageStorage;
        }
    
        public void run(){
            for(int i=0; i<5; i++){
                messageStorage.get();
            }
        }
    }


    测试代码:

    public class ThreadMain {
        public static void main(String[] args){
            MessageStorage messageStorage = new MessageStorage(10);
            Thread[] threads = new Thread[10];
            for (int i = 0; i < 5; i++) {
                Thread thread = new Thread(new Producer(messageStorage,i));//创建多个生产者
                threads[i] = thread;
            }
            for (int i = 0; i < 5; i++) {
                Thread thread = new Thread(new Consumer(messageStorage));//创建多个消费者
                threads[i+5] = thread;
            }
            for(int i = 0; i < 10; i++){
                Thread thread = threads[i];
                try {
                    thread.start();//启动线程
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    总结:

    使用wait()和notifyAll()/notify()方法,便于我们在程序中主动的控制的线程的休眠和唤醒 ,实现更为复杂的逻辑控制要求。另外,我们也可以使用Lock锁来进行代码控制,使用锁的条件Condition的await()和signal()/和signalAll()控制线程的休眠、唤醒,来实现上面的生产者-消费者模型。



  • 相关阅读:
    CentOS 7中cAdvisor的安装过程
    怎么查看centos版本
    使docker命令不用加sudo的方法
    Linux进程相关函数system,fork,exec函数族的区别
    git pre-commit hook failed 解决办法
    lint-staged 教程
    用webpack将多个scss文件打包成一个css文件
    js连按键盘事件
    vscode快捷键
    vim 操作命令大全
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6205014.html
Copyright © 2011-2022 走看看