一、前言
今天没事干的时候,无意间点到了一个System.out.println()中的println()方法,一个闪亮的关键字冲击着我的眼睛。
不知道大家知不知道,那就是加锁的synchronized。但凡有锁的地方肯定会性能是有损耗的,当然得在并发的情况下!
synchronized在JDK8还是6之后进入了锁升级概念:无锁--->偏向锁--->自旋锁--->轻量级锁--->重量级锁
「轻量级锁和偏向锁通常不涉及内核态切换」
「在到重量级锁时涉及到用户态和内核态的切换,很影响性能的!」
有兴趣的可以自己研究一下synchronized的锁升级和降级!
下面我们回归正题,看一下这个System.out.println()!
二、源码和分析
网上文章很多,大家想看System和out的详细解读,可以去看看哈,这里主要看一下println()这个方法的源码!
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
我们以传进来的是Object对象为例,其他类型比这个少了一个转化为String在输出!
这种方式通常被称为对象级别的锁,因为它是以对象为粒度进行同步的!
print(s);newLine();这两个操作在同一时间只被一个线程执行,以防止输出的内容被多个线程交织在一起,导致输出混乱。
这种同步是为了保证输出的可见性和一致性。当然也带来了性能的损耗,一般情况不会引起线程阻塞,当多个线程尝试同时访问同一个控制台输出时,由于控制台输出的同步性质,可能会导致线程竞争锁,从而导致程序响应慢!
当然在没有并发的场景中,使用一下也没什么,切记不要在输出里面加上大量的运算和转换逻辑。
「但是为了不给后期埋雷,咱们还是尽量不要使用。」
「可以使用专门的日志框架,如Log4j、Logback等,它们提供了更灵活的日志记录和输出控制。」
我们在查看一下:newLine()
我们会发现它也是一个加锁的方法!
private void newLine() {
try {
synchronized (this) {
ensureOpen();
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
里面的textOut.flushBuffer()也是有锁的!
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
我们在看一下ensureOpen()方法,然后一直点就会发现 write(String chars, int start, int count)也是加着锁的!
所以我们还是不要轻易在项目中使用哈,「咱们还是使用日志框架」,还能有不用的日志级别打印,多香!
每天一个小技巧哈!
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
if (len