首页 文章 精选 留言 我的

精选列表

搜索[加密工具],共10000篇文章
优秀的个人博客,低调大师

macOS 终端工具 iTerm2 被发现一个存在 7 年的重大漏洞

此漏洞会允许攻击者在用户电脑上远程执行命令,Mozilla 提醒用户应该立即主动升级软件。 iTerm2 是非常流行的终端模拟器,被许多开发者与系统管理员广泛使用,不少人甚至会用它来处理一些不受信任的数据,因此 MOSS(Mozilla Open Source Support Program) 这次选了 iTerm2,并委托 ROS(Radially Open Security)进行安全审核工作。 据了解,这个漏洞在 iTerm2 中已存在长达 7 年,目前分配到的编号为CVE-2019-9535。这个漏洞可以让攻击者在使用者电脑上执行命令。 说起漏洞,iTerm2 这个重大的安全漏洞由 MOSS 资助的安全审核团队发现,MOSS 于 2015 年成立,从那时起就开始为开源开发者提供资金支持、协助开源与自由软件的发展。同时还支持开源技术的安全审核,MOSS 的资金正是来自 Mozilla 基金会,以确保开源生态健康发展。 ROS 发现 iTerm2 中的 tmux 整合功能有严重的漏洞,而且漏洞至少已经存在 7 年。简单来说,在大多数情况下,允许攻击者可对终端产生输出,也就是能在用户的电脑上执行命令。ROS 提供了攻击的 demo,而视频内容主要是进行表达概念性验证,因此当用户连接到恶意的 SSH 服务器后,攻击者仅示范开启的计算机程序,实际上还可以进行更多恶意指令。 Mozilla 则提到,这个漏洞需要与用户进行一定程度的互动,然后攻击者才能进行后续的攻击行动,但是由于使用普遍认为安全的指令就会受到攻击,因此被认为有高度的潜在安全影响。现在 Mozilla、ROS 与 iTerm2 开发者密切合作,推出了最新 3.3.6 版本,而 3.3.5 的安全修补程式也已经发布。Mozilla 表示,虽然软件会主动提示更新,但是希望开发者能主动进 行更新,减少可能被攻击机会。 目前 iTerm2 开发者现在已经发布最新的 3.3.6 版本,Mozilla 也提醒使用者应该要尽快更新。

优秀的个人博客,低调大师

Twitter 开源高分辨率遥测工具 Rezolus,轻松捕获系统性能异常瞬间

Twitter 昨日宣布开源Rezolus,这是一种高分辨率遥测代理,旨在发现性能异常现象和利用率峰值,这些异常现象和峰值通常都太短暂,难以通过常规观察和系统指标来捕获。Rezolus有助于量化工作负载,提供数据以推进优化,并且已经用于诊断运行时的性能问题。Twitter 已经在 Rezolus 上运行了一年多。 “Rezolus 提供了一系列信号,以帮助我们理解细粒度的运行时行为。我们发现它对理解和优化性能特别有帮助”,Twitter 工程师 Brian Martin 在博客文章中写道,“通过单一代理,我们可以从各种来源获得遥测。据我们所知,没有其他开源项目能够在单个软件包中展现如此全面的洞察力。” 根据Martin 的说法,Rezolus 诞生于对了解细粒度时间尺度上的系统性能的需求。在运行非常高吞吐量的综合基准测试时,Twitter 工程师们有时会遇到短暂的性能异常,但现有的遥测技术采样率相对较低,因此未能反映出这些异常状况。 这是因为,根据采样定理,采样率必须至少是最短脉冲持续时间的两倍,以便准确地反映爆发的强度,而大多数遥测都会产生一个微小的时间序列。相比之下,Rezolus 可以在更加精确的时间尺度上精确测量性能下降的情况。 Rezolus 允许配置采样率,因此开发人员可以将分辨率与尖峰长度匹配,并且不会消耗过多的资源。在 10Hz 采样时,它能够反映出 200 毫秒或更长时间的连续突发,足以满足 Twitter 上的大多数服务。同时,在这一条件下它只占用不超过 15% CPU 和 60MB 内存。 可切换的插件采样器使 Rezolus 能够从各种来源收集遥测,包括来自 Linux kernel 源的计数器和仪表,以获得有关 CPU 使用率、网络利用率和磁盘利用率的遥测。这些采样器还可根据需要进行不同配置。 最后,Martin 写道:“开源 Rezolus 标志着该项目的一个重要里程碑,我们希望 Rezolus 对 Twitter 之外的其他人也有用,并期待围绕它建立一个社区。” 博客原文:https://blog.twitter.com/engineering/en_us/topics/open-source/2019/introducing-rezolus.html

优秀的个人博客,低调大师

python人工智能机器学习工具书籍: scikit-learn Cookbook 2nd Edition

简介 本书包括对机器学习中常见问题和不常见问题的演练和解决方案,以及如何利用scikit-learn有效地执行各种机器学习任务。 第二版首先介绍评估数据统计属性的方法,并为机器学习建模生成合成数据。当您逐步完成这些章节时,您会遇到一些食谱,它们将教您实施数据预处理,线性回归,逻辑回归,KNN,NaïveBayes,分类,决策树,合奏等技术。 此外,您将学习使用多级分类,交叉验证,模型评估来优化您的模型,并深入学习使用scikit-learn实现深度学习。 除了涵盖模型部分,API和分类器,回归器和估算器等新功能的增强功能外,本书还包含评估和微调模型性能的方法。在本书的最后,您将探索用于Python的scikit-learn提供的众多功能,以解决您遇到的任何机器学习问题。 参考资料 下载:https://www.jianshu.com/p/c2

优秀的个人博客,低调大师

[雪峰磁针石博客]2018最佳人工智能数据采集(爬虫)工具书下载

Python网络数据采集 Python网络数据采集 - 2016.pdf 本书采用简洁强大的Python语言,介绍了网络数据采集,并为采集新式网络中的各种数据类型提供了全面的指导。第 1部分重点介绍网络数据采集的基本原理:如何用Python从网络服务器请求信息,如何对服务器的响应进行基本处理,以及如何以自动化手段与网站进行交互。第 二部分介绍如何用网络爬虫测试网站,自动化处理,以及如何通过更多的方式接入网络。 Web Scraping with Python 2nd - 2018.pdf https://github.com/REMitchell/python-scraping 2000左右星 精通Python爬虫框架Scrapy Scrapy是使用Python开发的一个快速、高层次的屏幕抓取和Web抓取框架,用于抓Web站点并从页面中提取结构化的数据。《精通Python爬虫框架Scrapy》以Scrapy 1.0版本为基础,讲解了Scrapy的基础知识,以及如何使用Python和三方API提取、整理数据,以满足自己的需求。 本书共11章,其内容涵盖了Scrapy基础知识,理解HTML和XPath,安装Scrapy并爬取一个网站,使用爬虫填充数据库并输出到移动应用中,爬虫的强大功能,将爬虫部署到Scrapinghub云服务器,Scrapy的配置与管理,Scrapy编程,管道秘诀,理解Scrapy性能,使用Scrapyd与实时分析进行分布式爬取。本书附录还提供了各种软件的安装与故障排除等内容。本书适合软件开发人员、数据科学家,以及对自然语言处理和机器学习感兴趣的人阅读。 源码 github星级 300左右 Learning Scrapy -2016.pdf 另有中文电子版本 因为版权已经在CSDN等网站下架,可以在qq群144081101等找到。 python3爬虫基础 在线教程 https://github.com/MorvanZhou/easy-scraping-tutorial 200 左右星 First web scraper 教程:https://first-web-scraper.readthedocs.io/en/latest/ https://github.com/ireapps/first-web-scraper/blob/master/docs/index.rst 200 左右星 Practical Web Scraping for Data Science -Best Practices and Examples with Python - 2018.pdf https://github.com/Apress/practical-web-scraping-for-data-science 星级 低于100 This book provides a complete and modern guide to web scraping, using Python as the programming language, without glossing over important details or best practices. Written with a data science audience in mind, the book explores both scraping and the larger context of web technologies in which it operates, to ensure full understanding. The authors recommend web scraping as a powerful tool for any data scientist’s arsenal, as many data science projects start by obtaining an appropriate data set. Starting with a brief overview on scraping and real-life use cases, the authors explore the core concepts of HTTP, HTML, and CSS to provide a solid foundation. Along with a quick Python primer, they cover Selenium for JavaScript-heavy sites, and web crawling in detail. The book finishes with a recap of best practices and a collection of examples that bring together everything you've learned and illustrate various data science use cases. 用Python写网络爬虫 第2版 《用Python写网络爬虫(第 2版》讲解了如何使用Python来编写网络爬虫程序,内容包括网络爬虫简介,从页面中抓取数据的3种方法,提取缓存中的数据,使用多个线程和进程进行并发抓取,抓取动态页面中的内容,与表单进行交互,处理页面中的验证码问题,以及使用Scarpy和Portia进行数据抓取,并在最后介绍了使用本书讲解的数据抓取技术对几个真实的网站进行抓取的实例,旨在帮助读者活学活用书中介绍的技术。 《用Python写网络爬虫(第 2版》适合有一定Python编程经验而且对爬虫技术感兴趣的读者阅读。 Python Web Scraping 2nd Edition - 2017.pdf 第一版中文 用Python写网络爬虫.pdf https://github.com/kjam/wswp < 100星 Python Web Scraping Cookbook - 2018.pdf 下载 Python Web Scraping Cookbook is a solution-focused book that will teach you techniques to develop high-performance Scrapers, and deal with cookies, hidden form fields, Ajax-based sites and proxies. You'll explore a number of real-world scenarios where every part of the development or product life cycle will be fully covered. You will not only develop the skills to design reliable, high-performing data flows, but also deploy your codebase to Amazon Web Services (AWS). If you are involved in software engineering, product development, or data mining or in building data-driven products, you will find this book useful as each recipe has a clear purpose and objective. Right from extracting data from websites to writing a sophisticated web crawler, the book's independent recipes will be extremely helpful while on the job. This book covers Python libraries, requests, and BeautifulSoup. You will learn about crawling, web spidering, working with AJAX websites, and paginated items. You will also understand to tackle problems such as 403 errors, working with proxy, scraping images, and LXML. By the end of this book, you will be able to scrape websites more efficiently and deploy and operate your scraper in the cloud. https://github.com/PacktPublishing/Python-Web-Scraping-Cookbook < 100星 参考资料 https://github.com/lorien/awesome-web-scraping/blob/master/python.md 最好用的Python爬虫推荐 https://www.jianshu.com/p/7da43c16dd87 https://www.zhihu.com/question/41277528

优秀的个人博客,低调大师

[雪峰磁针石博客]数据分析工具pandas快速入门教程4-数据汇聚

我们需要的所有信息可能记录在单独的文件和数据帧中。例如,可能有一个公司信息单独表和股票价格表,数据被分成独立的表格以减少冗余信息。 连接 添加行 4-1.py import pandas as pd df1 = pd.read_csv('data/concat_1.csv') df2 = pd.read_csv('data/concat_2.csv') df3 = pd.read_csv('data/concat_3.csv') print(df1) print(df2) print(df3) row_concat = pd.concat([df1, df2, df3]) print(row_concat) print(row_concat.iloc[3, ]) new_row_series = pd.Series(['n1', 'n2', 'n3', 'n4']) print(pd.concat([df1, new_row_series])) new_row_df = pd.DataFrame([['n1', 'n2', 'n3', 'n4']], columns=['A', 'B', 'C', 'D']) print(new_row_df) print(pd.concat([df1, new_row_df])) print(df1.append(df2)) print(df1.append(new_row_df)) data_dict = {'A': 'n1', 'B': 'n2', 'C': 'n3', 'D': 'n4'} print(df1.append(data_dict, ignore_index=True)) row_concat_i = pd.concat([df1, df2, df3], ignore_index=True) print(row_concat_i) 执行结果 $ python3 4-1.py A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 A B C D 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 A B C D 0 a8 b8 c8 d8 1 a9 b9 c9 d9 2 a10 b10 c10 d10 3 a11 b11 c11 d11 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 0 a8 b8 c8 d8 1 a9 b9 c9 d9 2 a10 b10 c10 d10 3 a11 b11 c11 d11 A a3 B b3 C c3 D d3 Name: 3, dtype: object A B C D 0 0 a0 b0 c0 d0 NaN 1 a1 b1 c1 d1 NaN 2 a2 b2 c2 d2 NaN 3 a3 b3 c3 d3 NaN 0 NaN NaN NaN NaN n1 1 NaN NaN NaN NaN n2 2 NaN NaN NaN NaN n3 3 NaN NaN NaN NaN n4 A B C D 0 n1 n2 n3 n4 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 n1 n2 n3 n4 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 n1 n2 n3 n4 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 4 n1 n2 n3 n4 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 4 a4 b4 c4 d4 5 a5 b5 c5 d5 6 a6 b6 c6 d6 7 a7 b7 c7 d7 8 a8 b8 c8 d8 9 a9 b9 c9 d9 10 a10 b10 c10 d10 11 a11 b11 c11 d11 添加列 4-2.py In [1]: from numpy import NaN, NAN, nan In [2]: print(NaN == True, NaN == False, NaN == 0, NaN == '', sep='|') False|False|False|False In [3]: print(NaN == NaN, NaN == nan, NaN == NAN, nan == NAN, sep='|') False|False|False|False In [4]: import pandas as pd In [5]: print(pd.isnull(NaN), pd.isnull(nan), pd.isnull(NAN), sep='|') True|True|True In [6]: print(pd.notnull(NaN), pd.notnull(99), pd.notnull("https://china-testing.github.io"), sep='|') False|True|True 执行结果 $ python3 4-2.py A B C D A B C D A B C D 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11 A A A 0 a0 a4 a8 1 a1 a5 a9 2 a2 a6 a10 3 a3 a7 a11 A B C D A B C D A B C D new_col_list 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 n1 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 n2 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 n3 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11 n4 A B C D A B C D A B C D new_col_list \ 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 n1 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 n2 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 n3 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11 n4 new_col_series 0 n1 1 n2 2 n3 3 n4 0 1 2 3 4 5 6 7 8 9 10 11 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11 合并不同区间 4-3.py import pandas as pd df1 = pd.read_csv('data/concat_1.csv') df2 = pd.read_csv('data/concat_2.csv') df3 = pd.read_csv('data/concat_3.csv') df1.columns = ['A', 'B', 'C', 'D'] df2.columns = ['E', 'F', 'G', 'H'] df3.columns = ['A', 'C', 'F', 'H'] print(df1) print(df2) print(df3) row_concat = pd.concat([df1, df2, df3]) print(row_concat) print(pd.concat([df1, df2, df3], join='inner')) print(pd.concat([df1,df3], ignore_index=False, join='inner')) df1.index = [0, 1, 2, 3] df2.index = [4, 5, 6, 7] df3.index = [0, 2, 5, 7] print(df1) print(df2) print(df3) col_concat = pd.concat([df1, df2, df3], axis=1) print(col_concat) print(pd.concat([df1, df3], axis=1, join='inner')) 执行结果 $ python3 4-3.py A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 E F G H 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 A C F H 0 a8 b8 c8 d8 1 a9 b9 c9 d9 2 a10 b10 c10 d10 3 a11 b11 c11 d11 A B C D E F G H 0 a0 b0 c0 d0 NaN NaN NaN NaN 1 a1 b1 c1 d1 NaN NaN NaN NaN 2 a2 b2 c2 d2 NaN NaN NaN NaN 3 a3 b3 c3 d3 NaN NaN NaN NaN 0 NaN NaN NaN NaN a4 b4 c4 d4 1 NaN NaN NaN NaN a5 b5 c5 d5 2 NaN NaN NaN NaN a6 b6 c6 d6 3 NaN NaN NaN NaN a7 b7 c7 d7 0 a8 NaN b8 NaN NaN c8 NaN d8 1 a9 NaN b9 NaN NaN c9 NaN d9 2 a10 NaN b10 NaN NaN c10 NaN d10 3 a11 NaN b11 NaN NaN c11 NaN d11 Empty DataFrame Columns: [] Index: [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3] A C 0 a0 c0 1 a1 c1 2 a2 c2 3 a3 c3 0 a8 b8 1 a9 b9 2 a10 b10 3 a11 b11 A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 E F G H 4 a4 b4 c4 d4 5 a5 b5 c5 d5 6 a6 b6 c6 d6 7 a7 b7 c7 d7 A C F H 0 a8 b8 c8 d8 2 a9 b9 c9 d9 5 a10 b10 c10 d10 7 a11 b11 c11 d11 A B C D E F G H A C F H 0 a0 b0 c0 d0 NaN NaN NaN NaN a8 b8 c8 d8 1 a1 b1 c1 d1 NaN NaN NaN NaN NaN NaN NaN NaN 2 a2 b2 c2 d2 NaN NaN NaN NaN a9 b9 c9 d9 3 a3 b3 c3 d3 NaN NaN NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN NaN a4 b4 c4 d4 NaN NaN NaN NaN 5 NaN NaN NaN NaN a5 b5 c5 d5 a10 b10 c10 d10 6 NaN NaN NaN NaN a6 b6 c6 d6 NaN NaN NaN NaN 7 NaN NaN NaN NaN a7 b7 c7 d7 a11 b11 c11 d11 A B C D A C F H 0 a0 b0 c0 d0 a8 b8 c8 d8 2 a2 b2 c2 d2 a9 b9 c9 d9 合并多个数据集 4-4.py import pandas as pd person = pd.read_csv('data/survey_person.csv') site = pd.read_csv('data/survey_site.csv') survey = pd.read_csv('data/survey_survey.csv') visited = pd.read_csv('data/survey_visited.csv') print(person) print(site) print(survey) print(visited) visited_subset = visited.iloc[[0, 2, 6], ] o2o_merge = site.merge(visited_subset, left_on='name', right_on='site') print(o2o_merge) m2o_merge = site.merge(visited, left_on='name', right_on='site') print(m2o_merge) ps = person.merge(survey, left_on='ident', right_on='person') vs = visited.merge(survey, left_on='ident', right_on='taken') print(ps) print(vs) 执行结果 $ python3 4-4.py ident personal family 0 dyer William Dyer 1 pb Frank Pabodie 2 lake Anderson Lake 3 roe Valentina Roerich 4 danforth Frank Danforth name lat long 0 DR-1 -49.85 -128.57 1 DR-3 -47.15 -126.72 2 MSK-4 -48.87 -123.40 taken person quant reading 0 619 dyer rad 9.82 1 619 dyer sal 0.13 2 622 dyer rad 7.80 3 622 dyer sal 0.09 4 734 pb rad 8.41 5 734 lake sal 0.05 6 734 pb temp -21.50 7 735 pb rad 7.22 8 735 NaN sal 0.06 9 735 NaN temp -26.00 10 751 pb rad 4.35 11 751 pb temp -18.50 12 751 lake sal 0.10 13 752 lake rad 2.19 14 752 lake sal 0.09 15 752 lake temp -16.00 16 752 roe sal 41.60 17 837 lake rad 1.46 18 837 lake sal 0.21 19 837 roe sal 22.50 20 844 roe rad 11.25 ident site dated 0 619 DR-1 1927-02-08 1 622 DR-1 1927-02-10 2 734 DR-3 1939-01-07 3 735 DR-3 1930-01-12 4 751 DR-3 1930-02-26 5 752 DR-3 NaN 6 837 MSK-4 1932-01-14 7 844 DR-1 1932-03-22 name lat long ident site dated 0 DR-1 -49.85 -128.57 619 DR-1 1927-02-08 1 DR-3 -47.15 -126.72 734 DR-3 1939-01-07 2 MSK-4 -48.87 -123.40 837 MSK-4 1932-01-14 name lat long ident site dated 0 DR-1 -49.85 -128.57 619 DR-1 1927-02-08 1 DR-1 -49.85 -128.57 622 DR-1 1927-02-10 2 DR-1 -49.85 -128.57 844 DR-1 1932-03-22 3 DR-3 -47.15 -126.72 734 DR-3 1939-01-07 4 DR-3 -47.15 -126.72 735 DR-3 1930-01-12 5 DR-3 -47.15 -126.72 751 DR-3 1930-02-26 6 DR-3 -47.15 -126.72 752 DR-3 NaN 7 MSK-4 -48.87 -123.40 837 MSK-4 1932-01-14 ident personal family taken person quant reading 0 dyer William Dyer 619 dyer rad 9.82 1 dyer William Dyer 619 dyer sal 0.13 2 dyer William Dyer 622 dyer rad 7.80 3 dyer William Dyer 622 dyer sal 0.09 4 pb Frank Pabodie 734 pb rad 8.41 5 pb Frank Pabodie 734 pb temp -21.50 6 pb Frank Pabodie 735 pb rad 7.22 7 pb Frank Pabodie 751 pb rad 4.35 8 pb Frank Pabodie 751 pb temp -18.50 9 lake Anderson Lake 734 lake sal 0.05 10 lake Anderson Lake 751 lake sal 0.10 11 lake Anderson Lake 752 lake rad 2.19 12 lake Anderson Lake 752 lake sal 0.09 13 lake Anderson Lake 752 lake temp -16.00 14 lake Anderson Lake 837 lake rad 1.46 15 lake Anderson Lake 837 lake sal 0.21 16 roe Valentina Roerich 752 roe sal 41.60 17 roe Valentina Roerich 837 roe sal 22.50 18 roe Valentina Roerich 844 roe rad 11.25 ident site dated taken person quant reading 0 619 DR-1 1927-02-08 619 dyer rad 9.82 1 619 DR-1 1927-02-08 619 dyer sal 0.13 2 622 DR-1 1927-02-10 622 dyer rad 7.80 3 622 DR-1 1927-02-10 622 dyer sal 0.09 4 734 DR-3 1939-01-07 734 pb rad 8.41 5 734 DR-3 1939-01-07 734 lake sal 0.05 6 734 DR-3 1939-01-07 734 pb temp -21.50 7 735 DR-3 1930-01-12 735 pb rad 7.22 8 735 DR-3 1930-01-12 735 NaN sal 0.06 9 735 DR-3 1930-01-12 735 NaN temp -26.00 10 751 DR-3 1930-02-26 751 pb rad 4.35 11 751 DR-3 1930-02-26 751 pb temp -18.50 12 751 DR-3 1930-02-26 751 lake sal 0.10 13 752 DR-3 NaN 752 lake rad 2.19 14 752 DR-3 NaN 752 lake sal 0.09 15 752 DR-3 NaN 752 lake temp -16.00 16 752 DR-3 NaN 752 roe sal 41.60 17 837 MSK-4 1932-01-14 837 lake rad 1.46 18 837 MSK-4 1932-01-14 837 lake sal 0.21 19 837 MSK-4 1932-01-14 837 roe sal 22.50 20 844 DR-1 1932-03-22 844 roe rad 11.25 参考资料 技术支持qq群144081101 591302926 567351477 钉钉免费群21745728 本文最新版本地址 本文涉及的python测试开发库 谢谢点赞! 本文相关海量书籍下载 源码下载 本文英文版书籍下载

优秀的个人博客,低调大师

分布式系统开发工具包 —— 基于Hessian的HTTP RPC调用技术

Hessian官网:http://hessian.caucho.com/ hessian是二进制web service协议。 Hessian介绍 创建Hessian服务包括四个步骤: 创建Java接口,用于提供公开服务 使用HessianProxyFactory创建客户端 创建服务实现类 在servlet引擎中配置服务 HelloWorld服务 public interface BasicAPI { public String hello(); } 服务实现 public class BasicService extends HessianServlet implements BasicAPI { private String _greeting = "Hello, world"; public void setGreeting(String greeting) { _greeting = greeting; } public String hello() { return _greeting; } } 客户端实现 String url = "http://hessian.caucho.com/test/test"; HessianProxyFactory factory = new HessianProxyFactory(); BasicAPI basic = (BasicAPI) factory.create(BasicAPI.class, url); System.out.println("hello(): " + basic.hello()); 部署标准web.xml <web-app> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <param-name>home-class</param-name> <param-value>example.BasicService</param-value> </init-param> <init-param> <param-name>home-api</param-name> <param-value>example.Basic</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/hello</url-pattern> <servlet-name>hello</servlet-name> </servlet-mapping> </web-app> Hessian序列化 Hessian类可以用来做序列化与反序列化 序列化 Object obj = ...; OutputStream os = new FileOutputStream("test.xml"); Hessian2Output out = new Hessian2Output(os); out.writeObject(obj); os.close(); 反序列化 InputStream is = new FileInputStream("test.xml"); Hessian2Input in = new Hessian2Input(is); Object obj = in.readObject(null); is.close(); 如果要序列化比基础类型或String类型更加复杂的java对象,务必确保对象实现了java.io.Serializable接口。 Hessian处理大量数据 分布式应用需要发送大量二进制数据时,使用InputStream会更加有效率,因为它避免了分配大量byte数组。方法参数中只有最后一个参数可能是InputStream,因为数据是在调用过程中读的。 下面是一个上传文件的API的例子 package example; public interface Upload { public void upload(String filename, InputStream data); } 如果返回结果是InputStream,客户端必须在finally块中调用InputStream.close()方法,因为Hessian不会关闭底层HTTP流,直到所有数据被读取并且input stream被关闭。 文件下载API: package example; public interface Download { public InputStream download(String filename, InputStream data); } 文件下载实现: InputStream is = fileProxy.download("test.xml"); try { ... // read data here } finally { is.close(); } 原文发布于:http://www.yesdata.net/2018/03/11/hessian/

优秀的个人博客,低调大师

Java并发编程实战系列14之构建自定义的同步工具 (Building Custom Synchronizers)

类库中包含了许多存在状态依赖的类,例如FutureTask、Semaphore和BlockingQueue,他们的一些操作都有前提条件,例如非空,或者任务已完成等。 创建状态依赖类的最简单的房就是在JDK提供了的状态依赖类基础上构造。例如第八章的ValueLactch,如果这些不满足,可以使用Java语言或者类库提供的底层机制来构造,包括 内置的条件队列 condition AQS 这一章就介绍这些。 14.1 状态依赖性的管理 State Dependence 在14.2节会介绍使用条件队列来解决阻塞线程运行的问题。下面先介绍通过轮询和休眠的方式(勉强)的解决。 下面是一个标准的模板, void blockingAction() throws InterruptedException { acquire lock on object state while (precondition does not hold) { release lock wait until precondition might hold optionally fail if interrupted or timeout expires reacquire lock } perform action } 下面介绍阻塞有界队列的集中实现方式。依赖的前提条件是: 不能从空缓存中获取元素 不能将元素放入已满的缓存中 不满足条件时候,依赖状态的操作可以 抛出异常 返回一个错误状态(码) 阻塞直到进入正确的状态 下面是基类,线程安全,但是非阻塞。 @ThreadSafe public abstract class BaseBoundedBuffer <V> { @GuardedBy("this") private final V[] buf; @GuardedBy("this") private int tail; @GuardedBy("this") private int head; @GuardedBy("this") private int count; protected BaseBoundedBuffer(int capacity) { this.buf = (V[]) new Object[capacity]; } protected synchronized final void doPut(V v) { buf[tail] = v; if (++tail == buf.length) tail = 0; ++count; } protected synchronized final V doTake() { V v = buf[head]; buf[head] = null; if (++head == buf.length) head = 0; --count; return v; } public synchronized final boolean isFull() { return count == buf.length; } public synchronized final boolean isEmpty() { return count == 0; } } “先检查再运行”的逻辑解决方案如下,调用者必须自己处理前提条件失败的情况。当然也可以返回错误消息。 当然调用者可以不Sleep,而是直接重试,这种方法叫做忙等待或者自旋等待(busy waiting or spin waiting. ),如果换成很长时间都不变,那么这将会消耗大量的CPU时间!!!所以调用者自己休眠,sleep让出CPU。但是这个时间就很尴尬了,sleep长了万一一会前提条件就满足了岂不是白等了从而响应性低,sleep短了浪费CPU时钟周期。另外可以试试yield,但是这也不靠谱。 @ThreadSafe public class GrumpyBoundedBuffer <V> extends BaseBoundedBuffer<V> { public GrumpyBoundedBuffer() { this(100); } public GrumpyBoundedBuffer(int size) { super(size); } public synchronized void put(V v) throws BufferFullException { if (isFull()) throw new BufferFullException(); doPut(v); } public synchronized V take() throws BufferEmptyException { if (isEmpty()) throw new BufferEmptyException(); return doTake(); } } class ExampleUsage { private GrumpyBoundedBuffer<String> buffer; int SLEEP_GRANULARITY = 50; void useBuffer() throws InterruptedException { while (true) { try { String item = buffer.take(); // use item break; } catch (BufferEmptyException e) { Thread.sleep(SLEEP_GRANULARITY); } } } } 下一步改进下,首先让客户端舒服些。 @ThreadSafe public class SleepyBoundedBuffer <V> extends BaseBoundedBuffer<V> { int SLEEP_GRANULARITY = 60; public SleepyBoundedBuffer() { this(100); } public SleepyBoundedBuffer(int size) { super(size); } public void put(V v) throws InterruptedException { while (true) { synchronized (this) { if (!isFull()) { doPut(v); return; } } Thread.sleep(SLEEP_GRANULARITY); } } public V take() throws InterruptedException { while (true) { synchronized (this) { if (!isEmpty()) return doTake(); } Thread.sleep(SLEEP_GRANULARITY); } } } 这种方式测试失败,那么释放锁,让别人做,自己休眠下,然后再检测,不断的重复这个过程,当然可以解决,但是还是需要做权衡,CPU使用率与响应性之间的抉择。 那么我们想如果这种轮询和休眠的dummy方式不用,而是存在某种挂起线程的方案,并且这种方法能够确保党某个条件成真时候立刻唤醒线程,那么将极大的简化实现工作,这就是条件队列的实现。 Condition Queues的名字来源:it gives a group of threads called the wait set a way to wait for a specific condition to become true. Unlike typical queues in which the elements are data items, the elements of a condition queue are the threads waiting for the condition. 每个Java对象都可以是一个锁,每个对象同样可以作为一个条件队列,并且Object的wait、notify和notifyAll就是内部条件队列的API。对象的内置锁(intrinsic lock )和内置条件队列是关联的,要调用X中的条件队列的任何一个方法,都必须持有对象X上的锁。 Object.wait自动释放锁,并且请求操作系统挂起当前线程,从而其他线程可以获得这个锁并修改对象状态。当被挂起的线程唤醒时。它将在返回之前重新获取锁。 @ThreadSafe public class BoundedBuffer <V> extends BaseBoundedBuffer<V> { // CONDITION PREDICATE: not-full (!isFull()) // CONDITION PREDICATE: not-empty (!isEmpty()) public BoundedBuffer() { this(100); } public BoundedBuffer(int size) { super(size); } // BLOCKS-UNTIL: not-full public synchronized void put(V v) throws InterruptedException { while (isFull()) wait(); doPut(v); notifyAll(); } // BLOCKS-UNTIL: not-empty public synchronized V take() throws InterruptedException { while (isEmpty()) wait(); V v = doTake(); notifyAll(); return v; } // BLOCKS-UNTIL: not-full // Alternate form of put() using conditional notification public synchronized void alternatePut(V v) throws InterruptedException { while (isFull()) wait(); boolean wasEmpty = isEmpty(); doPut(v); if (wasEmpty) notifyAll(); } } 注意,如果某个功能无法通过“轮询和休眠"来实现,那么条件队列也无法实现。 14.2 Using Condition Queues 14.2.1 条件谓词The Condition Predicate The Condition Predicate 是使某个操作成为状态依赖操作的前提条件。take方法的条件谓词是”缓存不为空“,take方法在执行之前必须首先测试条件谓词。同样,put方法的条件谓词是”缓存不满“。 在条件等待中存在一种重要的三元关系,包括 加锁 wait方法 条件谓词 条件谓词中包含多个状态变量,而状态变量由一个锁来保护,因此在测试条件谓词之前必须先持有这个锁。锁对象和条件队列对象必须是同一个对象。wait释放锁,线程挂起阻塞,等待知道超时,然后被另外一个线程中断或者被一个通知唤醒。唤醒后,wait在返回前还需要重新获取锁,当线程从wait方法中唤醒,它在重新请求锁时不具有任何特殊的优先级,和其他人一起竞争。 14.2.2 过早唤醒 其他线程中间插足了,获取了锁,并且修改了遍历,这时候线程获取锁需要重新检查条件谓词。 wait block ----------race to get lock ------------------------------------------get lock ----- ^ wait block --------> race to get lock ------get lock------> perform action ---> release lock ^ notifyAll 当然有的时候,比如一个你根本不知道为什么别人调用了notify或者notifyAll,也许条件谓词压根就没满足,但是线程还是获取了锁,然后test条件谓词,释放所,其他线程都来了这么一趟,发生这就是“谎报军情”啊。 基于以上这两种情况,都必须重新测试条件谓词。 When using condition waits (Object.wait or Condition.await): Always have a condition predicate——some test of object state that must hold before proceeding; Always test the condition predicate before calling wait, and again after returning from wait; Always call wait in a loop; Ensure that the state variables making up the condition predicate are guarded by the lock associated with the condition queue; Hold the lock associated with the the condition queue when calling wait, notify, or notifyAll Do not release the lock after checking the condition predicate but before acting on it. 模板就是: void stateDependentMethod() throws InterruptedException { // condition predicate must be guarded by lock synchronized(lock) { while (!conditionPredicate()) //一定在循环里面做条件谓词 lock.wait(); //确保和synchronized的是一个对象 // object is now in desired state //不要释放锁 } } 14.2.3 丢失的信号 保证notify一定在wait之后 14.2.4 通知 下面介绍通知。 调用notify和notifyAll也得持有与条件队列对象相关联的锁。调用notify,JVM Thread Scheduler在这个条件队列上等待的多个线程中选择一个唤醒,而notifyAll则会唤醒所有线程。因此一旦notify了那么就需要尽快的释放锁,否则别人都竞争等着拿锁,都会进行blocked的状态,而不是线程挂起waiting状态,竞争都了不是好事,但是这是你考了性能因素和安全性因素的一个矛盾,具体问题要具体分析。 下面的方法可以进来减少竞争,但是确然程序正确的实现有些难写,所以这个折中还得自己考虑: public synchronized void alternatePut(V v) throws InterruptedException { while (isFull()) wait(); boolean wasEmpty = isEmpty(); doPut(v); if (wasEmpty) notifyAll(); } 使用notify容易丢失信号,所以大多数情况下用notifyAll,比如take notify,却通知了另外一个take,没有通知put,那么这就是信号丢失,是一种“被劫持的”信号。 因此只有满足下面两个条件,才能用notify,而不是notifyAll: 所有等待线程的类型都相同 单进单出 14.2.5 示例:阀门类A Gate Class 和第5章的那个TestHarness中使用CountDownLatch类似,完全可以使用wait/notifyAll做阀门。 @ThreadSafe public class ThreadGate { // CONDITION-PREDICATE: opened-since(n) (isOpen || generation>n) @GuardedBy("this") private boolean isOpen; @GuardedBy("this") private int generation; public synchronized void close() { isOpen = false; } public synchronized void open() { ++generation; isOpen = true; notifyAll(); } // BLOCKS-UNTIL: opened-since(generation on entry) public synchronized void await() throws InterruptedException { int arrivalGeneration = generation; while (!isOpen && arrivalGeneration == generation) wait(); } } 14.3 Explicit Condition Objects Lock是一个内置锁的替代,而Condition也是一种广义的内置条件队列。 Condition的API如下: public interface Condition { void await() throws InterruptedException; boolean await(long time, TimeUnit unit)throws InterruptedException; long awaitNanos(long nanosTimeout) throws InterruptedException; void awaitUninterruptibly(); boolean awaitUntil(Date deadline) throws InterruptedException; void signal(); void signalAll(); } 内置条件队列存在一些缺陷,每个内置锁都只能有一个相关联的条件队列,记住是一个。所以在BoundedBuffer这种累中,多个线程可能在同一个条件队列上等待不同的条件谓词,所以notifyAll经常通知不是同一个类型的需求。如果想编写一个带有多个条件谓词的并发对象,或者想获得除了条件队列可见性之外的更多的控制权,可以使用Lock和Condition,而不是内置锁和条件队列,这更加灵活。 一个Condition和一个lock关联,想象一个条件队列和内置锁关联一样。在Lock上调用newCondition就可以新建无数个条件谓词,这些condition是可中断的、可有时间限制的,公平的或者非公平的队列操作。 The equivalents of wait, notify, and notifyAll for Condition objects are await, signal, and signalAll。 下面的例子就是改造后的BoundedBuffer, @ThreadSafe public class ConditionBoundedBuffer <T> { protected final Lock lock = new ReentrantLock(); // CONDITION PREDICATE: notFull (count < items.length) private final Condition notFull = lock.newCondition(); // CONDITION PREDICATE: notEmpty (count > 0) private final Condition notEmpty = lock.newCondition(); private static final int BUFFER_SIZE = 100; @GuardedBy("lock") private final T[] items = (T[]) new Object[BUFFER_SIZE]; @GuardedBy("lock") private int tail, head, count; // BLOCKS-UNTIL: notFull public void put(T x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[tail] = x; if (++tail == items.length) tail = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } // BLOCKS-UNTIL: notEmpty public T take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); T x = items[head]; items[head] = null; if (++head == items.length) head = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } } 注意这里使用了signal而不是signalll,能极大的减少每次缓存操作中发生的上下文切换和锁请求次数。 使用condition和内置锁和条件队列一样,必须保卫在lock里面。 14.4 Synchronizer剖析 看似ReentrantLock和Semaphore功能很类似,每次只允许一定的数量线程通过,到达阀门时 可以通过 lock或者acquire 等待,阻塞住了 取消tryLock,tryAcquire 可中断的,限时的 公平等待和非公平等待 下面的程序是使用Lock做一个Mutex也就是持有一个许可的Semaphore。 @ThreadSafe public class SemaphoreOnLock { private final Lock lock = new ReentrantLock(); // CONDITION PREDICATE: permitsAvailable (permits > 0) private final Condition permitsAvailable = lock.newCondition(); @GuardedBy("lock") private int permits; SemaphoreOnLock(int initialPermits) { lock.lock(); try { permits = initialPermits; } finally { lock.unlock(); } } // BLOCKS-UNTIL: permitsAvailable public void acquire() throws InterruptedException { lock.lock(); try { while (permits <= 0) permitsAvailable.await(); --permits; } finally { lock.unlock(); } } public void release() { lock.lock(); try { ++permits; permitsAvailable.signal(); } finally { lock.unlock(); } } } 实际上很多J.U.C下面的类都是基于AbstractQueuedSynchronizer (AQS)构建的,例如CountDownLatch, ReentrantReadWriteLock, SynchronousQueue,and FutureTask(java7之后不是了)。AQS解决了实现同步器时设计的大量细节问题,例如等待线程采用FIFO队列操作顺序。AQS不仅能极大极少实现同步器的工作量,并且也不必处理竞争问题,基于AQS构建只可能在一个时刻发生阻塞,从而降低上下文切换的开销,提高吞吐量。在设计AQS时,充分考虑了可伸缩性,可谓大师Doug Lea的经典作品啊! 14.5 AbstractQueuedSynchronizer (AQS) 基于AQS构建的同步器勒种,最进步的操作包括各种形式的获取操作和释放操作。获取操作是一种依赖状态的操作,并且通常会阻塞。 如果一个类想成为状态依赖的类,它必须拥有一些状态,AQS负责管理这些状态,通过getState,setState, compareAndSetState等protected类型方法进行操作。这是设计模式中的模板模式。 使用AQS的模板如下: 获取锁:首先判断当前状态是否允许获取锁,如果是就获取锁,否则就阻塞操作或者获取失败,也就是说如果是独占锁就可能阻塞,如果是共享锁就可能失败。另外如果是阻塞线程,那么线程就需要进入阻塞队列。当状态位允许获取锁时就修改状态,并且如果进了队列就从队列中移除。 释放锁:这个过程就是修改状态位,如果有线程因为状态位阻塞的话就唤醒队列中的一个或者更多线程。 boolean acquire() throws InterruptedException { while (state does not permit acquire) { if (blocking acquisition requested) { enqueue current thread if not already queued block current thread } else return failure } possibly update synchronization state dequeue thread if it was queued return success } void release() { update synchronization state if (new state may permit a blocked thread to acquire) unblock one or more queued threads } 要支持上面两个操作就必须有下面的条件: 原子性操作同步器的状态位 阻塞和唤醒线程 一个有序的队列 1 状态位的原子操作 这里使用一个32位的整数来描述状态位,前面章节的原子操作的理论知识整好派上用场,在这里依然使用CAS操作来解决这个问题。事实上这里还有一个64位版本的同步器(AbstractQueuedLongSynchronizer),这里暂且不谈。 2 阻塞和唤醒线程 标准的JAVA API里面是无法挂起(阻塞)一个线程,然后在将来某个时刻再唤醒它的。JDK 1.0的API里面有Thread.suspend和Thread.resume,并且一直延续了下来。但是这些都是过时的API,而且也是不推荐的做法。 HotSpot在Linux中中通过调用pthread_mutex_lock函数把线程交给系统内核进行阻塞。 在JDK 5.0以后利用JNI在LockSupport类中实现了此特性。 LockSupport.park() LockSupport.park(Object) LockSupport.parkNanos(Object, long) LockSupport.parkNanos(long) LockSupport.parkUntil(Object, long) LockSupport.parkUntil(long) LockSupport.unpark(Thread) 上面的API中park()是在当前线程中调用,导致线程阻塞,带参数的Object是挂起的对象,这样监视的时候就能够知道此线程是因为什么资源而阻塞的。由于park()立即返回,所以通常情况下需要在循环中去检测竞争资源来决定是否进行下一次阻塞。park()返回的原因有三: 其他某个线程调用将当前线程作为目标调用 unpark; 其他某个线程中断当前线程; 该调用不合逻辑地(即毫无理由地)返回。 其实第三条就决定了需要循环检测了,类似于通常写的while(checkCondition()){Thread.sleep(time);}类似的功能。 3 有序队列 在AQS中采用CHL列表来解决有序的队列的问题。 AQS采用的CHL模型采用下面的算法完成FIFO的入队列和出队列过程。该队列的操作均通过Lock-Free(CAS)操作. 自己实现的CLH SpinLock如下: class ClhSpinLock { private final ThreadLocal<Node> prev; private final ThreadLocal<Node> node; private final AtomicReference<Node> tail = new AtomicReference<Node>(new Node()); public ClhSpinLock() { this.node = new ThreadLocal<Node>() { protected Node initialValue() { return new Node(); } }; this.prev = new ThreadLocal<Node>() { protected Node initialValue() { return null; } }; } public void lock() { final Node node = this.node.get(); node.locked = true; // 一个CAS操作即可将当前线程对应的节点加入到队列中, // 并且同时获得了前继节点的引用,然后就是等待前继释放锁 Node pred = this.tail.getAndSet(node); this.prev.set(pred); while (pred.locked) {// 进入自旋 } } public void unlock() { final Node node = this.node.get(); node.locked = false; this.node.set(this.prev.get()); } private static class Node { private volatile boolean locked; } } 对于入队列(enqueue):采用CAS操作,每次比较尾结点是否一致,然后插入的到尾结点中。 do { pred = tail; }while ( !compareAndSet(pred,tail,node) ); 对于出队列(dequeue):由于每一个节点也缓存了一个状态,决定是否出队列,因此当不满足条件时就需要自旋等待,一旦满足条件就将头结点设置为下一个节点。 AQS里面有三个核心字段: private volatile int state; private transient volatile Node head; private transient volatile Node tail; 其中state描述的有多少个线程取得了锁,对于互斥锁来说state<=1。head/tail加上CAS操作就构成了一个CHL的FIFO队列。下面是Node节点的属性。 独占操作的API都是不带有shared,而共享的包括semaphore和countdownlatch都是使用带有shared字面的API。 一些有用的参考资料: **java.util.concurrent.locks.AbstractQueuedSynchronizer - **AQS http://gee.cs.oswego.edu/dl/papers/aqs.pdf论文 http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一个比较全面的另外一个人的解读 http://suo.iteye.com/blog/1329460 http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-aqs-overview.html http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-aqs-clh-and-spin-lock.html http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-aqs-locksupport-and-thread-interrupt.html 独占的就用TRyAcquire, TRyRelease, and isHeldExclusively,共享的就用 tryAcquireShared and TRyReleaseShared. 带有try前缀的方法都是模板方法,AQS用于判断是否可以继续,例如如果tryAcquireShared返回一个负值,那么表示获取锁失败,失败的就需要进入CLH队列,并且挂起线程。 举一个例子,一个简单的闭锁。 @ThreadSafe public class OneShotLatch { private final Sync sync = new Sync(); public void signal() { sync.releaseShared(0); } public void await() throws InterruptedException { sync.acquireSharedInterruptibly(0); } private class Sync extends AbstractQueuedSynchronizer { protected int tryAcquireShared(int ignored) { // Succeed if latch is open (state == 1), else fail return (getState() == 1) ? 1 : -1; } protected boolean tryReleaseShared(int ignored) { setState(1); // Latch is now open return true; // Other threads may now be able to acquire } } } 下面是自己实现的一个Mutex。 /** * Lock free的互斥锁,简单实现,不可重入锁 */ public class Mutex implements Lock { private static final int FREE = 0; private static final int BUSY = 1; private static class LockSync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4689388770786922019L; protected boolean isHeldExclusively() { return getState() == BUSY; } public boolean tryAcquire(int acquires) { return compareAndSetState(FREE, BUSY); } protected boolean tryRelease(int releases) { if (getState() == FREE) { throw new IllegalMonitorStateException(); } setState(FREE); return true; } Condition newCondition() { return new ConditionObject(); } } private final LockSync sync = new LockSync(); public void lock() { sync.acquire(0); } public boolean tryLock() { return sync.tryAcquire(0); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(0); } public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(0); } } 14.6 J.U.C同步器勒种的AQS ReentrantLock protected boolean tryAcquire(int ignored) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, 1)) { owner = current; return true; } } else if (current == owner) { setState(c+1); return true; } return false; } Semaphore和CountDownLatch protected int tryAcquireShared(int acquires) { while (true) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } protected boolean tryReleaseShared(int releases) { while (true) { int p = getState(); if (compareAndSetState(p, p + releases)) return true; } }

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册