使用不同的Java库执行数百万个HTTP请求会让我挂起线程:
java.net.SocketInputStream.socketRead0()
哪个是native功能.
我试图设置Apche Http Client,并且RequestConfig(我希望)有一些可能的超时,但我仍然(可能无限)挂起socketRead0.如何摆脱它们?
挂起比率约为每10000个请求约1个(到10000个不同的主机)并且它可能永远持续(我已确认线程挂起仍然有效,10小时后仍然有效).
Windows 7上的JDK 1.8.
我的HttpClient工厂:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(false)
.setSoLinger(1)
.setSoReuseAddress(true)
.setSoTimeout(5000)
.setTcpNoDelay(true).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.disableAutomaticRetries();
builder.disableContentCompression();
builder.disableCookieManagement();
builder.disableRedirectHandling();
builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
builder.setDefaultSocketConfig(socketConfig);
return HttpClientBuilder.create().build();
Run Code Online (Sandbox Code Playgroud)
我的RequestConfig工厂:
HttpGet request = new HttpGet(url);
RequestConfig config = RequestConfig.custom()
.setCircularRedirectsAllowed(false)
.setConnectionRequestTimeout(8000)
.setConnectTimeout(4000)
.setMaxRedirects(1)
.setRedirectsEnabled(true)
.setSocketTimeout(5000)
.setStaleConnectionCheckEnabled(true).build();
request.setConfig(config);
return new HttpGet(url);
Run Code Online (Sandbox Code Playgroud)
注意:实际上我有一些"技巧" - 我可以.getConnectionManager().shutdown()在其他方面安排Thread取消,Future如果请求已正确完成,但它被删除,并且它也杀死了整个HttpClient,而不仅仅是单个请求.
我在StackOverflow的评论中读到了这个:
但是如果你想要安全,你可以在@PostConstruct [方法]的末尾添加简单的synchronized(this){}
[注意变量不易变化]
我认为只有当写入和读取都是在块中执行或者至少读取是易失性时才会强制执行synchronized.
引用的句子是否正确?空synchronized(this) {}块是否将当前方法中更改的所有变量刷新为"一般可见"内存?
请考虑一些场景
如果第二个线程从不调用锁定this怎么办?(假设第二个线程在其他方法中读取).请记住,问题是:刷新对其他线程的更改,而不是给其他线程一种方式(同步)来轮询原始线程所做的更改.在Spring @PostConstruct上下文中,很可能在其他方法中没有同步- 正如原始评论所说.
是仅在另一个线程的第二次和后续调用中强制执行的更改的内存可见性?(请记住,这个同步块是我们方法中的最后一个调用) - 这会将这种同步方式标记为非常糟糕的做法(第一次调用中的陈旧值)
假设我在Spring单例bean中做了一些初始化@PostConstruct(简化代码):
@Service
class SomeService {
public Data someData; // not final, not volatile
public SomeService() { }
@PostConstruct
public void init() {
someData = new Data(....);
}
}
Run Code Online (Sandbox Code Playgroud)
我应该担心someData其他豆类的可见性并标记它volatile吗?
(假设我无法在构造函数中初始化它)
第二种情况:如果我覆盖了值@PostConstruct(例如在构造函数中进行显式初始化或初始化之后),那么写入@PostConstruct 将不会首先写入此属性?
我创建了许多常见的小bean定义容器(@Configuration),我用它来快速开发Spring Boot应用程序,如:
@Import({
FreemarkerViewResolver.class, // registers freemarker that auto appends <#escape etc.
ConfigurationFromPropertiesFile.class, // loads conf/configuration.properties
UtfContentTypeResponse.class, // sets proper Content-language and Content-type
LocaleResolverWithLanguageSwitchController // Locale resolver + switch controller
);
class MySpringBootApp ...
Run Code Online (Sandbox Code Playgroud)
例如,其中一个@Configuration可以通过Web控制器为区域设置cookie设置会话存储,以切换到所选语言等.
使用和重用它们非常有趣,但是将它设置为参数化会非常棒,这可以允许更多的重用.我的意思是:
伪代码:
@Imports( imports = {
@FreemarkerViewResolver( escapeHtml = true, autoIncludeSpringMacros = true),
@ConfigurationFromProperties( path = "conf/configuration.properties" ),
@ContentTypeResponse( encoding = "UTF-8" ),
@LocaleResolver( switchLocaleUrl = "/locale/{loc}", defaultLocale = "en"
})
Run Code Online (Sandbox Code Playgroud)
所以,我的意思是"可配置@Configurations".以这种方式进行配置的最佳方法是什么?
也许更像这样的东西(再次,伪代码):
@Configuration
public …Run Code Online (Sandbox Code Playgroud) 假设我们拥有庞大而复杂的系统,其中包含大量数据和复杂的业务逻辑.
如何管理测试数据(Oracle DB)以从已知状态开始快速,可靠地接受(Selenium等)测试?
由于规模和复杂性,测试应该:
INSERTS到数据库 - 有风险的业务逻辑重复)当我们记录时:在函数调用之前(例子A)或在目标方法开始之前(例子B)?
请注意,此问题与准确的记录器函数调用位置有关,而不是一般的最佳日志记录实践.
解答A:登录函数调用:
function someProcess() {
log.info("Reading data");
readDataFromIO();
log.info("Outputing data");
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
...
}
function outputDataToScreen() {
...
}
Run Code Online (Sandbox Code Playgroud)
解决方案B:登录方法的开头
function someProcess() {
readDataFromIO();
outputDataToScreen();
}
// ... other module:
function readDataFromIO() {
log.info("Reading data");
...
}
function outputDataToScreen() {
log.info("Outputing data");
...
}
Run Code Online (Sandbox Code Playgroud)
在解决方案A中,您可以在效率问题上升时自定义消息或记录日志,但是如果日志消息看起来相同,您可以忘记记录并且有大量重复的代码.在解决方案B中,没有忘记日志记录和没有代码重复的风险,但是你不能100%关闭日志记录逻辑,如果在方法调用中出现错误,你就会遇到麻烦,比如空指针异常.这是最好的做法?
我使用Spring 3.2.5而没有全新的JSR-356 WebSockets支持.
我想在我的@ServerEndpointWebSocket服务器中使用singleton-bean引用,它由servlet容器本身实例化,而不是在Spring上下文中实例化.
干净的方法是什么?
我目前的解决方案:我@Service在静态字段中使用实例制作了单例bean:
@Service
public class WebSocketSupportBean {
private volatile static WebSocketSupportBean instance = null;
public static WebSocketSupportBean getInstance() {
return instance;
}
public WebSocketSupportBean() {
instance = this;
}
Run Code Online (Sandbox Code Playgroud)
并且只是@ServerEndpoint通过静态方法获取它,如果null返回则断开用户连接(如果在服务器启动期间bean没有创建但用户连接时):
从设计的角度来看,我想知道我应该测试数据,特别是如果它是一个通常已知的数据(不是非常可配置的) - 这可以适用于流行的文件扩展名,特殊的IP地址等.
假设我们有一个紧急电话号码分类器:
public class ContactClassifier {
public final static String EMERGENCY_PHONE_NUMBER = "911";
public boolean isEmergencyNumber(String number) {
return number.equals(EMERGENCY_PHONE_NUMBER);
}
}
Run Code Online (Sandbox Code Playgroud)
我应该这样测试("911"重复):
@Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber("911"));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
Run Code Online (Sandbox Code Playgroud)
或(测试是否正确识别"已配置"号码):
@Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber(ContactClassifier.EMERGENCY_PHONE_NUMBER));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
Run Code Online (Sandbox Code Playgroud)
或者在构造函数中注入"911",这看起来对我来说是最合理的,但即使我这样做 - 如果组件用适当的值实例化,我应该为"应用程序粘合剂"编写一个测试吗?如果有人可以在数据(代码)中输入拼写错误,那么我认为没有人可以在测试案例中输入拼写错误(我打赌这样的数据会被复制粘贴)
假设已经编写了不可更改的宿主程序,它通过socket接收这样的C++结构:
#pragma pack(push, 2)
struct Data {
double x;
double y;
double z;
long frameNumber;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)
平台:在Visual Studio 2008中编译的C++/32位Windows应用程序
如何从Java Socket发送这样的数据?我已经注意用putDouble()填充ByteBuffer,putLong(),putInt()假设长达32位,但我无法生成有效值.
我也随机生成和发送数据,并且结构级别的字节赋值看起来很好(我只能随机化一个值,例如X),但我不能产生精确的值(可能是不同的双重表示?),而只是通过发送随机的东西Math.random()*Double.MAX_VALUE;
我是否可以仅在一方(产生数据的客户端)上使用Google Protocol Buffers来解决此问题?
记住,我无法改变服务器(接收)方面
我知道我可以将数据发送到C++并使用JNI,但我正在寻找更简单的解决方案.
我在这里看到至少2个可能的问题:
这些东西在C++中用Java看起来是什么样的?
几个小时后,我将提供"字节黑客"的精确样本数据(发送前的确切Java值和C++中收到的double的值)
关于服务器坏设计回答
我知道这样的实现和不可更改的服务器是坏软件,但这个问题的环境是在"hobbistic-level"向小型旧应用程序注入一些数据
Java表示
也许这会对某些位级C++专家有所帮助:
Long.toBinaryString( Double.doubleToRawLongBits( (double) 0 ) );
// 000000000000000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1 ) );
// 011111111110000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1.1 ) );
// 011111111110001100110011001100110011001100110011001100110011010
Long.toBinaryString( Double.doubleToRawLongBits( 1024 ) );
// 100000010010000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1024.1024 ) );
// 100000010010000000000000110100011011011100010111010110001110001
Long.toBinaryString( Double.doubleToRawLongBits( Double.MAX_VALUE ) ); …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种方式来提供最快的(我的意思是零时间 -编译/类加载/ JIT时间分辨)可以开/关标志的if条件.当然,每次应用程序运行时,此条件只会更改一次 - 启动时.
我知道可以条件编译"条件编译时常量",并且可以从代码中删除整个条件.但是,无需重新编译源代码,最快(也可能是简单)的替代方案是什么?
我可以将条件移动到单独的.jar类和带条件的方法分开,在那里我生成两个版本.jar并在应用程序启动时在类路径中打开这些版本?将JIT删除调用方法在不同的.jar ,如果它发现,该方法是空的?
我可以通过在类路径中实现"ClassWithMyCondition"提供两个类来实现,其中一个类将具有真正的实现,第二个将只有空方法并实例化其中一个Class.forName和.newInstance()?将JIT从我的主要删除对空方法的调用非常循环嵌套的方法?
什么可以是最简单的字节码操作解决这个问题?
java ×9
spring ×3
concurrency ×2
sockets ×2
volatile ×2
annotations ×1
automation ×1
c++ ×1
classloader ×1
coding-style ×1
debugging ×1
double ×1
fixtures ×1
http ×1
jit ×1
jsr356 ×1
junit ×1
logging ×1
memory-model ×1
oracle ×1
performance ×1
selenium ×1
spring-3 ×1
spring-boot ×1
spring-mvc ×1
struct ×1
synchronized ×1
timeout ×1
unit-testing ×1
websocket ×1