V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Aresxue  ›  全部回复第 3 页 / 共 22 页
回复总数  434
1  2  3  4  5  6  7  8  9  10 ... 22  
小应用随便玩,大的这么玩,基于 http 接口的文档生成工具比如 swagger 就废了,你要自己手写接口文档还要维护,静态代码分析系统也没啥用了,一个应用就一个接口要干啥肯定不知道,全链路系统好一点,但也只能用 tid 去查,其它维度的查询都废了,监控告警系统基于接口的统计比如调用量、平均 rt 、95 线、97 线、99 线也都无了,简而言之可观测性被你全废了。
317 天前
回复了 nnegier 创建的主题 Java [Spring] WebSocket 怎么做到集群?
这问题想问的是推送,如何把某个用户的信息反向推送到浏览器,浏览器到用户有 nginx 代理 tcp 直接就能找到,这问题说大不大说小不小,简单来说就是维护 user 和 server 的关系,但如果 server 的量级超过 100 就会复杂的多,多活容灾每个细节都值得大费篇章。
319 天前
回复了 baolinliu442k 创建的主题 Java 实际项目中如何使用线程池
@Aresxue 其实可以把虚拟线程学起来了,有了这玩意之后绝大多数场景就不再需要线程池了,线程不会再成为应用的瓶颈,目前 jdk21 中的功能已经勉强可用,预计下个 LTS 版本能基本稳定下来。
319 天前
回复了 baolinliu442k 创建的主题 Java 实际项目中如何使用线程池
@baolinliu442k 并发度和 cpu 核数有关系但没太大关系,cpu 哪怕是单核因为时间片是轮转的从使用者视角来看任务都是并行的,回到你这个问题从普通的使用者视角可以认为同时执行 10 个任务,但如果是按真实的占用 cpu 去执行逻辑这个角度,哪怕你有 5 个核,这 5 个核同时被你的任务使用的时间几乎是没有的,因为还有 tomcat 线程、rpc 线程池等其它活跃的线程共享你的 5 个核。
320 天前
回复了 baolinliu442k 创建的主题 Java 实际项目中如何使用线程池
1.视业务而定,如果是一个低频的业务和其它业务共享一个线程池也无伤大雅,如果相对并发较高,最好是指定用自己的线程池而不是公用的线程池,@Async 也是可以指定线程池的,和 private static 的方式基本上是等价的,大多数情况下都可以用它;
2.参数没有标准,完完全全根据业务的情况而定,这个情况不仅是当下还有对未来的适当评估;
3.线程池主要是用于隔离线程资源和多参数任务并行降低 rt ,其对于整个应用资源的利用率并不会有显著的提升;
4. execute 适用于没有返回值的任务,submit 的返回值是 Future ,基本上能用 submit 没啥必要了,CompleteableFuture 本来就是为了加强 Future 的。

对于业务中我是建议能不能则不用,作为排名靠后的一个选择,顺便贴一些使用线程池的注意点:
- 合适的任务队列及其大小,过大会造成 oom ;
- ThreadLocal(登录信息上下文或其它的业务信息)丢失;
- 全链路 id 丢失;
- 合适的线程池策略和线程数(固定数目和不定数目);
- 任务重启丢失(优雅退出);
333 天前
回复了 zshineee 创建的主题 Java 请教一个 Java 查询 elasticsearch 的问题
应该不是服务端问题 ,用 arthas trace 一下看看,实际中 es 的连接数、反序列化都会影响最终的性能。
341 天前
回复了 errorMsg0xff 创建的主题 Java Java 值得读源码的开源项目
值得的:Netty
架构设计的好看的:Dubbo
理念完善的:Spring
实现巧妙的:AQS 、ConcurrentHashMap
贴近业务的:Rocketmq
341 天前
回复了 RichardX2023 创建的主题 Java Java -多线程事务无法完美实现吗
@RichardX2023 核心原因是 java.sql.Connection 不是线程安全的,所以每个线程只能独占一个链接,对于你说的 20 个任务 10 个 work 线程的情况可以对线程池加以改造,提交任务(必须是批量提交)的时候根据剩余可用连接分配一定数目的链接(这个算法决定了这个策略的健壮性),比如 20 个任务可以分配 5 个链接,然后每 4 个任务共享一个链接,当然这四个之间就要排队了对耗时的优化肯定没有一个任务一个线程效果这么好,但并发度确实也从 1 变成了 5 。
345 天前
回复了 javak 创建的主题 Java 曾经我以为 Java21 的虚拟线程是银弹...
软件工程没有银弹。
synchronized 是可以在后续被 JVM 优化掉的,而且实在不行替换成 ReentrantLock 的操作也还是比较简单的。ThreadLocal 才麻烦,不过 scoped value 成熟后应该也可以搞的定。
就是现阶段替换虚拟线程的成本和收益不明显而已,但如果是一个长远规划的项目早做早好,小项目玩玩也可以。
345 天前
回复了 tnhmcm 创建的主题 Java Spring 里怎样正确处理 InterruptedException?
@Aresxue 有些地方有口误,InterruptedException 是个 checked exception ,翻译成中文是必须要检查( throw or catch )的异常
345 天前
回复了 tnhmcm 创建的主题 Java Spring 里怎样正确处理 InterruptedException?
尽量不要用 Thread.currentThread().interrupt() ,InterruptedException 其实最好是抛出去,业务代码里除非是为了解耦主流程和辅助流程、批处理循环时隔离单条的失败等情况不建议 catch 异常,这个事情恶心的一个点在于 InterruptedException 是个 unchecked exceptions ,向上抛 java 会强制你修改你的方法签名,如果不想这么干就直接将其包装成一个运行时异常再抛出去类似 throw new PackageException(e)这样,然后在全局异常处理的地方不捕获后 unpackage 再对其做相应处理。
典型的 apm 场景,这块做的最好是 arms ,支持接口统计、聚合和下钻,不想花钱就自己整 pinpoint 或 skywalking ,parms 就是基于 pinpoint 改的,你甚至还能在 arms 的 agent 看见 pinpoint 的包名。。pinpoint 的问题就是吃资源,性能开销大但是相对好用,可以临时上上去跑一段时间查查问题,查完了再下掉。skywalking 可以作为长久方案,性能开销确实小一些,但自带的 ui 太难用,对于你这个问题各种聚合信息你可能还需要自己去 es 里面查,而且由于其实极其复杂维护是个老大难的问题。
易用性:arms > pinpoint > skywalking
性能开销:arms = pinpoint > skywalking
可维护性: arms > pinpoint > skywalking

只针对问题本身也可以通过别的方式解决,首先保证数据库请求超时会输出异常日志,核心信息是时间,然后就是统计 http 接口的信息,nginx 、tomcat 、spring-boot-starter-actuator 、jmx 都可以做这件事情,最好用的是 spring-boot-starter-actuator 结合 promethues ,可以清楚的看到每个接口在指定时间段的频次、rt ,从 grafana 上直接就能看出流量的峰谷。
1.语法,这点说实话 go 做的也一般,C#明显做的更好;
2.预占内存, jvm 的内存是直接分配的,对于中小项目内存的利用率不充分,这一点在稍大一点的企业级项目里并不是问题;
3.启动慢,其实本身 jvm 没有那么慢,传统应用慢主要受两个东西拖累,一个是 spring(用了太多反射以及 bean 必须串行注册),另一个是 UrlClassLoader 加载类的逻辑(这一点阿里自定义了一个 FastUrlClassLoader 优化了很多,实测应用启动时间可以降低 1/2~2/3);
4.对象头、字节对齐等各种操作导致在偏硬件的软件系统中性能很低下,没法充分利用寄存器,甚至容器到现在还不支持基本类型;

但我还是看好 java 的未来,庞大的生态,我心中最好的 VM(你可以永远相信 JVM)。官方也有一直在做事情:Loom 、Valhalla 、Amber ,虚拟线程也已经发布了,准备好埋葬异步编程回到 thread-per-request 的时代吧。
https://github.com/tdebatty/java-string-similarity
推荐标准莱茵斯坦算法和余弦算法,字符串较大就用余弦,对准确率要求高就莱茵斯坦算法。
附上测试一个测试类自己修改下,用自己的实际数据多跑跑

public class SimilarityAlgorithmTest {

@Test
public void test() {
String str1 = "ares";
String str2 = "kele";

LevenshteinDistance levenshtein = LevenshteinDistance.getDefaultInstance();
System.out.println("Levenshtein distance: " + levenshtein.apply(str1, str2));
System.out.println("Levenshtein distance: " + levenshtein.apply(str2, str2));

LevenshteinDistance levenshteinWithThreshold = new LevenshteinDistance(3);
// Returns -1 since the actual distance, 4, is higher than the threshold
System.out.println("Levenshtein distance: " + levenshteinWithThreshold.apply(str1, str2));

LevenshteinDetailedDistance levenshteinDetailed = LevenshteinDetailedDistance.getDefaultInstance();
System.out.println("Levenshtein detailed distance: " + levenshteinDetailed.apply(str1, str2));
}

@Test
public void testLevenshteinDistance() {
int sLength = 13_162;
int strLength = 4_000;
String s = StringUtil.random(sLength);
String s1 = StringUtil.random(strLength) + s;
String s2 = StringUtil.random(strLength) + s;

int threshold = 4_096;
LevenshteinDistance levenshtein = new LevenshteinDistance(threshold);
long startTime = System.currentTimeMillis();
/*
threshold 为 32766 时花费 7022ms
threshold 为 16384 时花费 2164ms
threshold 为 8192 时花费 463ms
threshold 为 4096 时花费 146ms
threshold 为 2048 时花费 62ms
threshold 为 1024 时花费 41ms
threshold 为 512 时花费 29ms
*/
Integer result = levenshtein.apply(s1, s2);
System.out.println(System.currentTimeMillis() - startTime);
System.out.println("Levenshtein distance: " + result);

/*
这种是截取模式比较靠前的指定字符
threshold 为 4096 时花费 67ms
*/
levenshtein = LevenshteinDistance.getDefaultInstance();
startTime = System.currentTimeMillis();
result = levenshtein.apply(s1.substring(0, threshold), s2.substring(0, threshold));
System.out.println(System.currentTimeMillis() - startTime);
System.out.println("Levenshtein distance: " + result);
System.out.println();

result = levenshtein.apply(s1, s2);
System.out.println("Levenshtein: " + (1.0 - (double) result / (strLength + sLength)));
NormalizedLevenshtein normalizedLevenshtein = new NormalizedLevenshtein();
double similarity = normalizedLevenshtein.similarity(s1, s2);
System.out.println("NormalizedLevenshtein: " + similarity);
Jaccard jaccard = new Jaccard();
similarity = jaccard.similarity(s1, s2);
System.out.println("Jaccard: " + similarity);
Cosine cosine = new Cosine();
similarity = cosine.similarity(s1, s2);
System.out.println("Cosine: " + similarity);
QGram qGram = new QGram();
similarity = qGram.distance(s1, s2);
System.out.println("QGram: " + (1.0 - similarity / (strLength + sLength)));
}


@Test
public void testAlgorithmPerformance() {
String s1 = StringUtil.random(13_162);
String s2 = StringUtil.random(13_162);

LevenshteinDistance levenshtein = LevenshteinDistance.getDefaultInstance();
long startTime = System.currentTimeMillis();
levenshtein.apply(s1, s2);
System.out.println("LevenshteinDistance:" + (System.currentTimeMillis() - startTime));

NormalizedLevenshtein normalizedLevenshtein = new NormalizedLevenshtein();
startTime = System.currentTimeMillis();
normalizedLevenshtein.distance(s1, s2);
System.out.println("NormalizedLevenshtein: " + (System.currentTimeMillis() - startTime));

JaroWinkler jaroWinkler = new JaroWinkler();
startTime = System.currentTimeMillis();
jaroWinkler.distance(s1, s2);
System.out.println("JaroWinkler: " + (System.currentTimeMillis() - startTime));

LongestCommonSubsequence longestCommonSubsequence = new LongestCommonSubsequence();
startTime = System.currentTimeMillis();
longestCommonSubsequence.apply(s1, s2);
System.out.println("LongestCommonSubsequence: " + (System.currentTimeMillis() - startTime));

info.debatty.java.stringsimilarity.MetricLCS metricLCS = new info.debatty.java.stringsimilarity.MetricLCS();
startTime = System.currentTimeMillis();
metricLCS.distance(s1, s2);
System.out.println("MetricLCS: " + (System.currentTimeMillis() - startTime));

QGram qGram = new QGram();
startTime = System.currentTimeMillis();
qGram.distance(s1, s2);
System.out.println("QGram: " + (System.currentTimeMillis() - startTime));

Cosine cosine = new Cosine();
startTime = System.currentTimeMillis();
cosine.distance(s1, s2);
System.out.println("Cosine: " + (System.currentTimeMillis() - startTime));

Jaccard jaccard = new Jaccard();
startTime = System.currentTimeMillis();
jaccard.distance(s1, s2);
System.out.println("Jaccard: " + (System.currentTimeMillis() - startTime));
}

@Test
public void testCosine() {
String s1 = StringUtil.random(1_000_000);
String s2 = StringUtil.random(1_000_000);

Cosine cosine = new Cosine();
long startTime = System.currentTimeMillis();
cosine.distance(s1, s2);
System.out.println("Cosine: " + (System.currentTimeMillis() - startTime));
}

}
最简单的就是找文档,没文档就只能自求多福了,其实本身 dll 和 maven 依赖一样都是第三方库,但由于需求不是强所以 dll 的名单从来都没有地方管理, 我理解可以做个类似 Python requirements.txt 的东西管理起来,本来 jdk 做这个事情是最合适的,其次就是 maven 插件也可以做,但现在没有任何标准的话除了翻源码就是在测试环境多测测了(保持和生产环境一致)。
DynamicDataSourceContextHolder push 完之后要手动 poll 的,最好使用注解自动就做掉了免得自己忘了造成线程污染
2023-11-22 10:35:19 +08:00
回复了 steelshadow39 创建的主题 程序员 业务系统日志存储选型讨论
fluentbit + ELK, 这个是最流行的商业级方案,小项目就存文件算了吧,切好片做好格式等日志规范是最实用的,出于学习目的就上 loki
2023-11-14 14:33:40 +08:00
回复了 gomorebug 创建的主题 Java 关于 mybatis 的疑惑
@bill110100 orm 的全称是 Object/Relational Mapping ,比较典型的特征就是你只管操作对象框架会帮你把对象的变更映射到数据库,mybatis 本身只是存放 sql 不存在有时候连表对应的对象可能都不会存在,mybatis plus 才是 orm ,而如果要说到更纯正的 orm 还要用到 Active Record 模式,像 python 中的 SQLAlchemy 、c#的 Entity Framework 都是比较纯正的 orm 。
2023-11-13 11:33:39 +08:00
回复了 likre 创建的主题 Java 大佬们,求教一个技术问题
这个场景反射就是最简单的方案。
2023-11-13 11:26:47 +08:00
回复了 objcat 创建的主题 Java Java 如何优雅地在 main 方法执行前后执行代码
1.agent + 字节码改写 这个组合几乎可以做任何事情,但引入 agent 其实是个成本很高的事情还是要慎重;
2.静态代理 对方法有入侵;
3.定义一个函数把 main 传进去;
4.字节码改写有三个时机,编译期织入、装载期织入、运行期织入,完全可以像 lombok 那样做一个编译期织入的注解,关键词 AbstractProcessor ;
1  2  3  4  5  6  7  8  9  10 ... 22  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2741 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 26ms · UTC 12:15 · PVG 20:15 · LAX 04:15 · JFK 07:15
Developed with CodeLauncher
♥ Do have faith in what you're doing.