java集合之SynchronousQueue

SynchronousQueue也是一个队列,与其他队列不同的是,SynchronousQueue队列中,他不存储数据,存储生产者或者是消费者,让生产者和消费者直接交换手中的数据,任何一个写操作必须等到一个读操作(反之亦然),交换成功才是成功,否则就阻塞或者返回失败(取决于调用的方法)。
生产者最终会有几种结果:

  • 如果在阻塞期间有消费者来匹配,生产者就会将绑定的消息交给消费者
  • 生产者得等阻塞结果,或者不允许阻塞,那么就直接失败
  • 生产者在阻塞期间,如果线程中断,直接告辞。
    同理,消费者和生产者的效果是一样。
    在这里插入图片描述
    使用例子
public static void main(String[] args) throws ExecutionException, InterruptedException {
        SynchronousQueue synchronousQueue = new SynchronousQueue();
        Thread thread = new Thread(() -> {
            try {
                synchronousQueue.put("消息");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        });
        thread.start();

        Thread.sleep(1000);

        System.out.println("获取数据:"+synchronousQueue.poll());
    }
1、内部类结构

抽象类Transferer 提供了transfer方法,生产者或者消费者最终调用的都是这个方法
底层的数据结构提供了两种,队列和栈(TransferQueue,TransferStack)
生产者调用transfer方法的时候,第一个参数e就是需要传递的数据
消费者调用transfer方法的时候,第一个参数e为null

    abstract static class Transferer<E> {
        abstract E transfer(E e, boolean timed, long nanos);
    }
    static final class TransferStack<E> extends Transferer<E> {
    	...
    }
    static final class TransferQueue<E> extends Transferer<E> {
    	...
    }

SynchronousQueue针对抽象类Transferer做了2种实现。

  • TransferStack
  • TransferQueue
    这两种类继承了Transferer抽象类,在构建SynchronousQueue时,会指定使用哪种子类
   // 到底采用哪种实现,需要把对应的对象存放到这个属性中
	private transient volatile Transferer<E> transferer;
	// 采用无参时,会调用下述方法,再次调用有参构造传入false
	public SynchronousQueue() {
	    this(false);
	}
	// 调用的是当前的有参构造,fair代表公平还是不公平
	public SynchronousQueue(boolean fair) {
	    // 如果是公平,采用Queue(先进先出),如果是不公平,采用Stack(后进先出)
	    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
	}
2、源码
2.1 QNode
static final class QNode {
	// 下一个节点
   volatile QNode next;  
   // item在不同情况下效果不同
   // 生产者:有数据
   // 消费者:为null       
   volatile Object item;   
   // 当前线程    
   volatile Thread waiter;
   // 当前属性是区分消费者和生产者的属性      
   final boolean isData;
	// 最终生产者需要将item交给消费者
    // 最终消费者需要获取生产者的item
   ...
}
2.2 transfer方法实现
// 当前方法是TransferQueue的核心内容
// e:传递的数据
// timed:false,代表无限阻塞,true,代表阻塞nacos时间
E transfer(E e, boolean timed, long nanos) {
	// 当前QNode是要封装当前生产者或者消费者的信息
   QNode s = null;
   // isData == true:代表是生产者
   // isData == false:代表是消费者
   boolean isData = (e != null);
   // 死循环
   for (;;) {
   		// 队列头尾
       QNode t = tail;
       QNode h = head;
       // 为了避免TransferQueue还没有初始化,这边做一个健壮性判断
       if (t == null || h == null)         
           continue;  
           // h == t 头尾相等,说明是第一个节点     
           // t.isData == isData 如果有节点,同时当前节点和队列节点属于同一种角色      
           // if中的逻辑是进到队列     
       if (h == t || t.isData == isData) { 
       		// 获取尾节点的下一个元素 避免并发操作
           QNode tn = t.next;
           // 如果t和现在的tail不相等,说明有人操作了队列并添加了新的元素
           if (t != tail)  
           		// 重新走for循环                   
               continue;
           // 如果t==tail,但是tn为不null,说明前面有线程并发,添加了一个节点,
           // 但是还没来得及修改tail,那么我就帮他修改 修改完我再重新进来
           if (tn != null) {               
               advanceTail(t, tn);
               continue;
           }
           	// 获取当前线程是否可以阻塞
            // 如果timed为true,并且阻塞的时间小于等于0
            // 不需要匹配,直接告辞
           if (timed && nanos <= 0)       
               return null;
           // 如果可以阻塞,将当前需要插入到队列的QNode构建出来
           if (s == null)
               s = new QNode(e, isData);
           // 基于CAS操作,将tail节点的next设置为当前节点
           if (!t.casNext(null, s))   
           		// 修改失败则重来     
               continue;
           // CAS操作成功,直接替换tail的指向
           advanceTail(t, s);       
           // 如果进到队列中了,挂起线程,要么等生产者,要么等消费者。
           // x是返回替换后的数据      
           Object x = awaitFulfill(s, e, timed, nanos);
           // 如果x的值等于s,说明节点取消了
           if (x == s) {   
           		// 清空取消节点,返回null                
               clean(t, s);
               return null;
           }
           // 交换完成 判断当前节点是否还在队列中
           if (!s.isOffList()) {  
               // 将当前节点设置为head    
               advanceHead(t, s);    
               // 如果 x != null, 如果拿到了数据,说明我是消费者      
               if (x != null)     
               	   // 将当前节点的item置为自己	        
                   s.item = s;
               // 将节点中的线程置为null
               s.waiter = null;
           }
           // 返回数据
           return (x != null) ? (E)x : e;
       } else {      
       		// 匹配队列中的角色    
       		// 拿到head的next,作为要匹配的节点                   
           QNode m = h.next;     
           // 做并发判断,如果头节点,尾节点,或者head.next发生了变化,这边要重新走for循环  
           if (t != tail || m == null || h != head)
               continue; 
           // 没并发问题,可以拿数据
           // 拿到m节点的item作为x。              
           Object x = m.item;
           // isData == (x != null) 表示匹配的角色与当前角色一致(消费者匹配消费者,生产者匹配生产者)
           if (isData == (x != null) ||  
           		// x == m  如果排队的节点取消,就会将当前QNode中的item指向QNode 
               x == m || 
               // 如果前面两个都没满足,可以交换数据了。 
               // 如果交换失败,说明有并发问题,                  
               !m.casItem(x, e)) {
               //更换头节点 重新匹配         
               advanceHead(h, m);         
               continue;
           }
           // 替换head
           advanceHead(h, m);
           // 唤醒head.next中的线程             
           LockSupport.unpark(m.waiter);
            // 这边匹配好了,数据也交换了,直接返回
            // 如果 x != null,说明队列中是生产者,当前是消费者,这边直接返回x具体数据
            // 反之,队列中是消费者,当前是生产者,直接返回自己的数据
           return (x != null) ? (E)x : e;
       }
   }
}
基于 NSFW Model 色情图片识别鉴黄 后面更新视频检测 项目背景: 随着互联网的快速发展,网络上的信息量呈现出爆炸式的增长。然而,互联网上的内容良莠不齐,其中不乏一些不良信息,如色情、暴力等。这些信息对青少年的健康成长和社会风气产生了不良影响。为了净化网络环境,保护青少年免受不良信息的侵害,我国政府加大了对网络内容的监管力度。在此背景下,本项目应运而生,旨在实现对网络图片和视频的自动识别与过滤,助力构建清朗的网络空间。 项目简介: 本项目基于 NSFW(Not Safe For Work)Model,利用深度学习技术对色情图片进行识别与鉴黄。NSFW Model 是一种基于卷积神经网络(CNN)的图像识别模型,通过学习大量的色情图片和非色情图片,能够准确地判断一张图片是否含有色情内容。本项目在 NSFW Model 的基础上,进一步优化了模型结构,提高了识别的准确率和效率。 项目功能: 色情图片识别:用户上传图片后,系统会自动调用 NSFW Model 对图片进行识别,判断图片是否含有色情内容。如果含有色情内容,系统会给出相应的提示,并阻止图片的传播。 视频检测:针对网络视频,本项目采用帧提取技术,将视频分解为一帧帧图片,然后使用 NSFW Model 对这些图片进行识别。如果检测到含有色情内容的图片,系统会给出相应的提示,并阻止视频的传播。 实时监控:本项目可应用于网络直播、短视频平台等场景,实时监控画面内容,一旦检测到含有色情内容的画面,立即进行屏蔽处理,确保网络环境的纯洁。
### 如何在本地部署 NSFW 模型或服务 要在本地环境中成功部署 NSFW(不适宜工作场合内容)检测模型或服务,以下是详细的说明: #### 准备环境 为了确保能够顺利运行模型和服务,需要安装必要的依赖项。这些工具和库包括但不限于以下几类: - **Python 环境**: 推荐使用 Python 3.7 或更高版本。 - **Transformers 库**: 提供加载预训练模型的功能[^1]。 - **PyTorch/TensorFlow**: 支持深度学习框架的计算需求。 - **Pillow (PIL)**: 处理图像文件并将其转换为适合输入模型的形式。 具体命令如下所示: ```bash pip install transformers torch Pillow ``` #### 加载模型与测试 通过 Hugging Face 的 `transformers` 工具包可以直接访问已有的 NSFW 图片分类模型。例如,可以采用名为 `"Falconsai/nsfw_image_detection"` 的公开模型来完成此任务[^1]。 下面是一个简单的代码片段展示如何加载该模型并对单张图片执行预测操作: ```python from PIL import Image from transformers import pipeline def classify_nsfw(image_path): # 打开指定路径下的图片文件 img = Image.open(image_path) # 初始化 image-classification 流水线对象,并指明使用的特定模型名称 classifier = pipeline("image-classification", model="Falconsai/nsfw_image_detection") # 对传入的图片调用流水线方法得到其类别标签及其置信度分数列表形式的结果 result = classifier(img) return result if __name__ == "__main__": test_img_path = "<your_test_image>" output_results = classify_nsfw(test_img_path) print(output_results) ``` 注意替换 `<your_test_image>` 成实际存在的图片绝对或者相对地址字符串值之前再尝试运行以上脚本。 #### 构建 RESTful API 服务 如果希望进一步扩展功能至 Web 应用程序层面,则可考虑利用 Flask/Django 这样的轻量级 web 开发框架构建起支持 HTTP 请求交互的服务端接口。这里给出基于 FastAPI 实现的一个简单例子作为示范用途: ```python import uvicorn from fastapi import FastAPI, File, UploadFile from PIL import Image from io import BytesIO from typing import List from pydantic import BaseModel app = FastAPI() class Prediction(BaseModel): label: str score: float @app.post("/predict/", response_model=List[Prediction]) async def predict(file: UploadFile = File(...)): try: contents = await file.read() pil_image = Image.open(BytesIO(contents)) clf_pipeline = pipeline('image-classification', model='Falconsai/nsfw_image_detection') predictions = clf_pipeline(pil_image) formatted_preds = [{"label": pred['label'], "score": round(pred['score'], 4)} for pred in predictions] return formatted_preds except Exception as e: raise ValueError(f"Error processing uploaded file {e}") if __name__ == '__main__': uvicorn.run(app, host='0.0.0.0', port=8000) ``` 启动服务器之后即可向 `/predict/` 路径发送 POST 请求附带上传待分析的目标图片获取返回结果了。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值