Just Do Java

Java 's Blog


  • 首页

  • 分类

  • 作者

  • 归档

  • 关于

一文看懂 Redis 的内存回收策略和 Key 过期策略

发表于 2019-11-16 | 分类于 Redis

01、前言

Redis 作为当下最热门的 Key-Value 存储系统,在大大小小的系统中都扮演着重要的角色,不管是 session 存储还是热点数据的缓存,亦或是其他场景,我们都会使用到 Redis。在生产环境我们偶尔会遇到 Redis 服务器内存不够的情况,那对于这种情况 Redis 的内存是如何回收处理的呢?另外对于带有过期时间的 Key Redis 又是如何处理的呢?

阅读全文 »

Flink 基础学习(四)转换 Transformation

发表于 2019-11-12 | 分类于 Flink

前言

前面写了如何使用 Flink 读取常用的数据源,也简单介绍了如何进行自定义扩展数据源,本篇介绍它的下一步:数据转换 Transformation,其中数据处理用到的函数,叫做算子 Operator,下面是算子的官方介绍。

算子将一个或多个 DataStream 转换为新的 DataStream。程序可以将多种转换组合成复杂的数据流拓扑。

阅读全文 »

程序员,别再迷恋多线程工作了

发表于 2019-11-11 | 分类于 java

我刚刚尝试了一下,一边用 iPad 看“Java 极客技术”自制的 SpringBoot 视频(1.2X 倍速),一边在 iMac 上回复博客上读者的留言。过了一会,视频上讲了什么,我完全没有印象了;而回复的内容也写得乱七八糟。

阅读全文 »

灵魂拷问:Java 的 substring() 是如何工作的?

发表于 2019-11-11 | 分类于 life

在逛 programcreek 的时候,我发现了一些小而精悍的主题。比如说:Java 的 substring() 方法是如何工作的?像这类灵魂拷问的主题,非常值得深入地研究一下。

阅读全文 »

手把手教你实现热更新功能,带你了解 Arthas 热更新背后的原理

发表于 2019-11-10 | 分类于 Java

一、前言

一天下午正在摸鱼的时候,测试小姐姐走了过来求助,说是需要改动测试环境 mock 应用。但是这个应用一时半会又找不到源代码存在何处。但是测试小姐姐的活还是一定要帮,突然想起了 Arthas 可以热更新应用代码,按照网上的步骤,反编译应用代码,加上需要改动的逻辑,最后热更新成功。对此,测试小姐姐很满意,并表示下次会少提 Bug。

嘿嘿,以前一直对热更新背后原理很好奇,借着这个机会,研究一下热更新的原理。

阅读全文 »

带你涨姿势的认识一下Kafka-Producer

发表于 2019-11-08 | 分类于 Kafka

上一篇文章我们主要介绍了什么是 Kafka,Kafka 的基本概念是什么,Kafka 单机和集群版的搭建,以及对基本的配置文件进行了大致的介绍,还对 Kafka 的几个主要角色进行了描述,我们知道,不管是把 Kafka 用作消息队列、消息总线还是数据存储平台来使用,最终是绕不过消息这个词的,这也是 Kafka 最最核心的内容,Kafka 的消息从哪里来?到哪里去?都干什么了?别着急,一步一步来,先说说 Kafka 的消息从哪来。

阅读全文 »

CentOS7 下搭建 Harbor 仓库以及登录

发表于 2019-11-07 | 分类于 k8s

手把手教会你在 CentOS7 环境下搭建 Harbor 仓库,以及使用 Docker 以 HTTP 方式登录 Harbor 仓库。

阅读全文 »

关于 HTTP 代理,你还需要了解这些,不然面试你是过不去的!

发表于 2019-11-07 | 分类于 HTTP系列

上一篇文章我们完整的介绍了 HTTP 是如何使用 TCP 进行连接的,接下来的文章我们再来看看你在面试中经常会被问到的关于代理的问题。

阅读全文 »

灵魂拷问:为什么 Java 字符串是不可变的?

发表于 2019-11-06 | 分类于 java

在逛 programcreek 的时候,发现了一些精妙绝伦的主题。比如说:为什么 Java 字符串是不可变的?像这类灵魂拷问的主题,非常值得深思。

阅读全文 »

【集合系列】- 深入浅出的分析 Hashtable

发表于 2019-11-05 | 分类于 数据结构

Hashtable 一个元老级的集合类,早在 JDK 1.0 就诞生了,今天小编想和大家一起来揭开它的面纱!

阅读全文 »

【集合系列】- 深入浅出的分析 Set集合

发表于 2019-11-05 | 分类于 Java

前几篇文章中,咱们聊到 List、Map 接口相关的实现类,今天咱们来聊聊集合中的 Set 接口!

阅读全文 »

【集合系列】- 深入浅出的分析 Properties

发表于 2019-11-05 | 分类于 Java

最近在看 java 集合源码的时候,发现原来我们经常使用的 Properties 类既然继承自 Hashtable!又涨见识了!

阅读全文 »

面试的时候问你HTTP是如何使用TCP连接的你还不知道怎么回答么?今天我就来告诉你!

发表于 2019-11-05 | 分类于 HTTP系列

之前我写了篇关于 HTTP 的文章,文章中讲述了 HTTP的特点,HTTP 的报文,HTTP 的请求方式等知识,接下来,深入了,我们就关于 HTTP 引发的面试题来进行入手,一起来看一下吧!

阅读全文 »

从 Java 的平台无关性引入的一系列面试题

发表于 2019-11-04 | 分类于 面试

在 Java 面试中,有一条很常见的询问路线:从对 Java 的认识,到谈 Java 的平台无关性,到 Java 中的反射机制,再到类加载机制,继而深入到双亲委派机制等。本文将根据这条路线,给出一份可供参考的回答,如有错误万望指正。(推荐读者们在回答的时候结合自己的认识和项目经历作答)

阅读全文 »

java并发编程之线程基础

发表于 2019-11-04 | 分类于 java线程

01、简介

百丈高楼平地起,要想学好多线程,首先还是的了解一下线程的基础,这边文章将带着大家来了解一下线程的基础知识。

02、线程的创建方式

  1. 实现 Runnable 接口
  2. 继承 Thread 类
  3. 实现 Callable 接口通过 FutureTask 包装器来创建线程
  4. 通过线程池创建线程

​ 下面将用线程池和 ``Callable 的方式来创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CallableDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        int a=1;
        int b=2;
        System. out .println(a+b);
        return "执行结果:"+(a+b);
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建一个可重用固定线程数为1的线程池
        ExecutorService executorService = Executors.newFixedThreadPool (1);
        CallableDemo callableDemo=new CallableDemo();
        //执行线程,用future来接收线程的返回值
        Future<String> future = executorService.submit(callableDemo);
        //打印线程的返回值
        System. out .println(future.get());
        executorService.shutdown();
    }
}

执行结果

1
2
3
执行结果:3

03、线程的生命周期

  1. NEW:初始状态,线程被构建,但是还没有调用 start 方法。
  2. RUNNABLED:运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中”。调用线程的 start() 方法使线程进入就绪状态。
  3. BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了 CPU 使用权。比如访问 synchronized 关键字修饰的方法,没有获得对象锁。
  4. Waiting :等待状态,比如调用wait()方法。
  5. TIME_WAITING:超时等待状态,超时以后自动返回。比如调用 sleep(long millis) 方法
  6. TERMINATED:终止状态,表示当前线程执行完毕。

看下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum State {
        
        NEW,

        RUNNABLE,
        
        BLOCKED,
         
        WAITING,
       
        TIMED_WAITING,
        
        TERMINATED;
}

04、线程的优先级

  1. 线程的最小优先级:1
  2. 线程的最大优先级:10
  3. 线程的默认优先级:5
  4. 通过调用 getPriority() 和 setPriority(int newPriority) 方法来获得和设置线程的优先级

看下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	/**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

    /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

看下代码:

1
2
3
4
5
6
7
8
9
public class ThreadA extends Thread {

    public static void main(String[] args) {
        ThreadA a = new ThreadA();
        System.out.println(a.getPriority());//5
        a.setPriority(8);
        System.out.println(a.getPriority());//8
    }
}
线程优先级特性:
  1. 继承性:比如A线程启动B线程,则B线程的优先级与A是一样的。
  2. 规则性:高优先级的线程总是大部分先执行完,但不代表高优先级线程全部先执行完。
  3. 随机性:优先级较高的线程不一定每一次都先执行完。

05、线程的停止

  1. stop() 方法,这个方法已经标记为过时了,强制停止线程,相当于kill -9。
  2. interrupt() 方法,优雅的停止线程。告诉线程可以停止了,至于线程什么时候停止,取决于线程自身。

看下停止线程的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class InterruptDemo {
    private static int i ;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            //默认情况下isInterrupted 返回 false、通过 thread.interrupt 变成了 true
            while (!Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("Num:" + i);
        }, "interruptDemo");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt(); //不加这句,thread线程不会停止
    }
}

看上面这段代码,主线程main方法调用 thread线程的 interrupt() 方法,就是告诉 thread 线程,你可以停止了(其实是将 thread 线程的一个属性设置为了true),然后 thread 线程通过 isInterrupted() 方法获取这个属性来判断是否设置为了true。这里我再举一个例子来说明一下,

看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ThreadDemo {
    private volatile static Boolean interrupt = false ;
    private static int i ;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!interrupt) {
                i++;
            }
            System.out.println("Num:" + i);
        }, "ThreadDemo");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        interrupt = true;
    }
}

是不是很相似,再简单总结一下:

当其他线程通过调用当前线程的 interrupt 方法,表示向当前线程打个招呼,告诉他可以中断线程的执行了,并不会立即中断线程,至于什么时候中断,取决于当前线程自己。

线程通过检查资深是否被中断来进行相应,可以通过 isInterrupted() 来判断是否被中断。

这种通过标识符来实现中断操作的方式能够使线程在终止时有机会去清理资源,而不是武断地将线程停止,因此这种终止线程的做法显得更加安全和优雅。

06、线程的复位

两种复位方式:

  1. Thread.interrupted()
  2. 通过抛出 InterruptedException 的方式

然后了解一下什么是复位:

线程运行状态时 Thread.isInterrupted() 返回的线程状态是 false,然后调用 thread.interrupt() 中断线程 Thread.isInterrupted() 返回的线程状态是 true,最后调用 Thread.interrupted() 复位线程Thread.isInterrupted() 返回的线程状态是 false 或者抛出 InterruptedException 异常之前,线程会将状态设为 false。

下面来看下两种方式复位线程的代码,首先是 Thread.interrupted() 的方式复位代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class InterruptDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                //Thread.currentThread().isInterrupted()默认是false,当main方式执行thread.interrupt()时,状态改为true
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("before:" + Thread.currentThread().isInterrupted());//before:true
                    Thread.interrupted(); // 对线程进行复位,由 true 变成 false
                    System.out.println("after:" + Thread.currentThread().isInterrupted());//after:false
                }
            }
        }, "interruptDemo");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
    }
}

抛出 InterruptedException 复位线程代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class InterruptedExceptionDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // break;
                }
            }
        }, "interruptDemo");
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

结果:

1
2
3
4
5
6
7
false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.cl.concurrentprogram.InterruptedExceptionDemo.lambda$main$0(InterruptedExceptionDemo.java:16)
	at java.lang.Thread.run(Thread.java:748)

需要注意的是,InterruptedException 异常的抛出并不意味着线程必须终止,而是提醒当前线程有中断的操作发生,至于接下来怎么处理取决于线程本身,比如

  1. 直接捕获异常不做任何处理
  2. 将异常往外抛出
  3. 停止当前线程,并打印异常信息

像我上面的例子,如果抛出 InterruptedException 异常,我就break跳出循环让 thread 线程终止。

为什么要复位:

Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号,但不会立刻中断自己,具体什么时候中断由自己决定,让外界知道在自身中断前,他的中断状态仍然是 false,这就是复位的原因。

阅读全文 »

最常见的12道计算机网络面试题

发表于 2019-11-03 | 分类于 面试题

本篇总结了12道最常见的计算机网络面试题,并给出了一些自己的看法,若有不妥之处万望指正。

阅读全文 »

Dubbo 优雅停机演进之路

发表于 2019-10-30 | 分类于 Dubbo

一、前言

在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理。接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如何实现优雅停机。

阅读全文 »

Java 中令人匪夷所思的 Magic 之魔数

发表于 2019-10-24 | 分类于 java基础

01、故事背景

试想一下你现在有个业务场景需要你识别出各种类型的文件,然后进行不同的处理,这些文件不管是用户上传还是怎么来的,你都需要知道文件是什么类型,比如是一张 JPG 图片,还是一个 GIF 图片又或者是 PDF 等等其他类型的文件。这个时候你会想,这还不简单么,几行 Java 代码就搞定了。

阅读全文 »

Flink 基础学习(三)数据源 DataSource

发表于 2019-10-24 | 分类于 Flink

为何要使用 Flink

因为本篇文章中,有个 Kafka 数据源的 Demo,在一开始解答小伙伴有可能的困惑:

Question:既然监听 Kafka 消息,为何不建立一个简单的消息消费者,使用简单的代码就能进行消息的消费?

Answer:在普通的消费者逻辑中,只能做到对传送过来的一条消息进行单条处理。而在 Flink 这个优秀的流计算框架中,能够使用窗口进行多样化处理。提供了窗口处理函数,可以对一段时间(例如 5s 内)或者一批(计数大小,例如 5 个一批)的数据进行计数或者 reduce 整合处理

还有 Flink 拥有状态管理,能够保存 checkpoint,如果程序出现错误,也能够之前的检查点恢复,继续程序的处理,于是拥有这些好处的优秀框架,希望小伙伴也加入进来,一起学习~

阅读全文 »

到底是存在还是不存在之 BloomFilter

发表于 2019-10-22 | 分类于 java基础

01、什么是 BloomFilter(布隆过滤器)

布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。主要用于判断一个元素是否在一个集合中。通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,这个时候往往我们都是采用 Hashmap,Set 或者其他集合将数据保存起来,然后进行对比判断,但是如果元素很多的情况,我们如果采用这种方式就会非常浪费空间。这个时候我们就需要 BloomFilter 来帮助我们了。

阅读全文 »
1 … 19 20 21 … 32
Java Geek Tech

Java Geek Tech

一群热爱 Java 的技术人

633 日志
116 分类
24 作者
RSS
GitHub 知乎
Links
  • 纯洁的微笑
  • 沉默王二
  • 子悠
  • 江南一点雨
  • 炸鸡可乐
  • 郑璐璐
  • 程序通事
  • 懿
© 2019 - 2022 Java Geek Tech
由 Jekyll 强力驱动
主题 - NexT.Mist