如何下载OpenJDK及其源码
如果想下载 OpenJDK,存在以下几种办法:
最简单的办法是去 OpenJDK 官网,这里能下载 JDK9 及其以上的版本,还有 JDK 源码所在的 github 地址。
如果想下载 OpenJDK,存在以下几种办法:
最简单的办法是去 OpenJDK 官网,这里能下载 JDK9 及其以上的版本,还有 JDK 源码所在的 github 地址。
封装了从 1970-01-01T00:00:00Z 开始的秒数,相当于时间戳。
主要有两个属性:
private final long seconds;
private final int nanos;
用于表示日期,包括年、月、日,例如 2017-12-03。
主要有三个属性:
private final int year;
private final short month;
private final short day;
用于表示时间,包括时、分、秒,例如 10:15:30。
主要有四个属性:
private final byte hour;
private final byte minute;
private final byte second;
private final int nano; //纳秒
符合 ISO-8601 时间表示标准,用于表示日期和时间,包括年、月、日、时、分、秒,例如 2007-12-03T10:15:30。LocalDateTime 不包含时区信息。
LocalDateTime 只有两个属性:
private final LocalDate date; //日期
private final LocalTime time; //时间
包含日期、时间、时区信息,例如 2007-12-03T10:15:30+01:00 Europe/Paris
主要有三个属性:
private final LocalDateTime dateTime; //时间
private final ZoneOffset offset; //相对于UTC的偏移量
private final ZoneId zone; //时区
众所周知,如果想把 LocalDateTime 转为时间戳,需要先指定时区,然后才能转为时间戳,例如:
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
long second = zonedDateTime.toEpochSecond();
但是既然 LocalDateTime(本地时间)已经确定当前时间,为什么不能直接转为时间戳?
因为时间戳指的是自 1970 年 1 月 1 日(00:00:00 UTC/GMT)以来的秒数,所以无论在哪个时区,同一时间获取的都是相同时间戳,可以用于跨时区。但是我们现实生活用到的本地时间是跟时区挂钩的,中国所在的时区是东八区,会比 UTC 时间快 8 个小时。时间戳是从 UTC 时间得来的,所以时间戳与本地时间的相互转换,需要根据时区来转换。
先看一下下面的例子:
服务端代码为:
public class TimeServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();
try{
ServerBootstrap b=new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) {
channel.pipeline().addLast(new TimeServerHandler());
}
});
ChannelFuture f=b.bind(8081).sync();
f.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
class TimeServerHandler extends SimpleChannelInboundHandler {
private int counter;
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf=(ByteBuf)msg;
byte[] req=new byte[buf.readableBytes()];
buf.readBytes(req);
String body=new String(req, StandardCharsets.UTF_8);
System.out.println(body+",counter:"+ (++counter));
}
}
客户端代码为:
public class TimeClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group=new NioEventLoopGroup();
try{
Bootstrap b=new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel){
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture f=b.connect("127.0.0.1",8081).sync();
f.channel().closeFuture().sync();
}finally {
group.shutdownGracefully();
}
}
}
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
byte[] req= ("send msg to server\r\n").getBytes(StandardCharsets.UTF_8);
for (int i = 0; i < 3; i++) {
ByteBuf msg= Unpooled.buffer(req.length);
msg.writeBytes(req);
ctx.writeAndFlush(msg);
}
}
}
上面的代码中,客户端会连续发三条信息给服务端,服务端接收信息并进行计数。
或许你会认为服务端会收到三条信息,但事实上服务端可能只会收到一条,结果为:
send msg to server\send msg to server\send msg to server,counter:1
这是因为发生了粘包。粘包指的是多个小的数据包可能被封装成一个大的数据包发送。与之相关的是拆包,拆包指的是一个完整的数据包可能会被 TCP 拆分成多个包进行发送。
关于 AQS,网上已经有无数的文章阐述 AQS 的使用及其源码,所以多这么一篇文章也没啥所谓,还能总结一下研究过的源码。源码解析和某某的使用,大概是互联网上 Java 文章中写得最多的主题了。
AQS 是 AbstractQueuedSynchronizer 的缩写,中文翻译过来就是抽象队列同步器。ReentrantLock
、ReentrantReadWriteLock
、Semaphore
、CountDownLatch
都是基于 AQS。AQS 的核心思想是,当线程请求获取资源时,如果资源空闲,则会将当前线程设置为资源的独占线程,成功获得锁;否则将获取锁失败的线程加入到排队队列中(CLH),并提供线程阻塞和线程唤醒机制。CLH 是一个虚拟的双向队列。