日期与工夫

Date和Calendar

计算机示意的工夫是以整数示意的工夫戳存储的,即Epoch Time,Java应用long型来示意以毫秒为单位的工夫戳,通过System.currentTimeMillis()获取以后工夫戳。

Java有两套日期和工夫的API:

  • 旧的Date、Calendar和TimeZone;
  • 新的LocalDateTime、ZonedDateTime、ZoneId等。

别离位于java.utiljava.time包中。

Date

java.util.Date是用于示意一个日期和工夫的对象,留神与java.sql.Date辨别,后者用在数据库中。如果察看Date的源码,能够发现它实际上存储了一个long类型的以毫秒示意的工夫戳

       // 获取以后工夫:        Date date = new Date();        System.out.println(date.getYear() + 1900); // 必须加上1900        System.out.println(date.getMonth() + 1); // 0~11,必须加上1        System.out.println(date.getDate()); // 1~31,不能加1        // 转换为String:        System.out.println(date.toString());        // 转换为GMT时区:        System.out.println(date.toGMTString());        // 转换为本地时区:        System.out.println(date.toLocaleString());

留神getYear()返回的年份必须加上1900getMonth()返回的月份是0~11别离示意1~12月,所以要加1,而getDate()返回的日期范畴是1~31,又不能加1。

打印本地时区示意的日期和工夫时,不同的计算机可能会有不同的后果。如果咱们想要针对用户的偏好准确地管制日期和工夫的格局,就能够应用SimpleDateFormat对一个Date进行转换。

Calendar

Calendar能够用于获取并设置年、月、日、时、分、秒,它和Date比,次要多了一个能够做简略的日期和工夫运算的性能。

LocalDateTime

从Java 8开始,java.time包提供了新的日期和工夫API,次要波及的类型有:

  • 本地日期和工夫:LocalDateTimeLocalDateLocalTime
  • 带时区的日期和工夫:ZonedDateTime
  • 时刻:Instant
  • 时区:ZoneIdZoneOffset
  • 工夫距离:Duration

以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter

和旧的API相比,新API严格辨别了时刻、本地日期、本地工夫和带时区的日期工夫,并且,对日期和工夫进行运算更加不便。

此外,新API修改了旧API不合理的常量设计:

  • Month的范畴用1~12示意1月到12月;
  • Week的范畴用1~7示意周一到周日。

最初,新API的类型简直全副是不变类型(和String相似),能够放心使用不用放心被批改。

多线程

多线程是Java最根本的一种并发模型

多线程根底

古代操作系统(Windows,macOS,Linux)都能够执行多任务。多任务就是同时运行多个工作,例如:

CPU执行代码都是一条一条程序执行的,然而,即便是单核cpu,也能够同时运行多个工作。因为操作系统执行多任务实际上就是让CPU对多个工作轮流交替执行。

例如,假如咱们有语文、数学、英语3门作业要做,每个作业须要30分钟。咱们把这3门作业看成是3个工作,能够做1分钟语文作业,再做1分钟数学作业,再做1分钟英语作业,这样轮流做上来,在某些人眼里看来,做作业的速度就十分快,看上去就像同时在做3门作业一样。
相似的,操作系统轮流让多个工作交替执行,例如,让浏览器执行0.001秒,让QQ执行0.001秒,再让音乐播放器执行0.001秒,在人看来,CPU就是在同时执行多个工作。
即便是多核CPU,因为通常工作的数量远远多于CPU的核数,所以工作也是交替执行的。

过程

在计算机中,咱们把一个工作称为一个过程,浏览器就是一个过程,视频播放器是另一个过程,相似的,音乐播放器和Word都是过程。

某些过程外部还须要同时执行多个子工作。例如,咱们在应用Word时,Word能够让咱们一边打字,一边进行拼写查看,同时还能够在后盾进行打印,咱们把子工作称为线程。

过程和线程的关系就是:一个过程能够蕴含一个或多个线程,但至多会有一个线程。

                        ┌──────────┐                        │Process   │                        │┌────────┐│            ┌──────────┐││ Thread ││┌──────────┐            │Process   ││└────────┘││Process   │            │┌────────┐││┌────────┐││┌────────┐│┌──────────┐││ Thread ││││ Thread ││││ Thread │││Process   ││└────────┘││└────────┘││└────────┘││┌────────┐││┌────────┐││┌────────┐││┌────────┐│││ Thread ││││ Thread ││││ Thread ││││ Thread │││└────────┘││└────────┘││└────────┘││└────────┘│└──────────┘└──────────┘└──────────┘└──────────┘┌──────────────────────────────────────────────┐│               Operating System               │└──────────────────────────────────────────────┘

操作系统调度的最小工作单位其实不是过程,而是线程。罕用的Windows、Linux等操作系统都采纳抢占式多任务,如何调度线程齐全由操作系统决定,程序本人不能决定什么时候执行,以及执行多长时间。

因为同一个应用程序,既能够有多个过程,也能够有多个线程,因而,实现多任务的办法,有以下几种:

多过程模式(每个过程只有一个线程):

┌──────────┐ ┌──────────┐ ┌──────────┐│Process   │ │Process   │ │Process   ││┌────────┐│ │┌────────┐│ │┌────────┐│││ Thread ││ ││ Thread ││ ││ Thread │││└────────┘│ │└────────┘│ │└────────┘│└──────────┘ └──────────┘ └──────────┘

多线程模式(一个过程有多个线程):

┌────────────────────┐│Process             ││┌────────┐┌────────┐│││ Thread ││ Thread │││└────────┘└────────┘││┌────────┐┌────────┐│││ Thread ││ Thread │││└────────┘└────────┘│└────────────────────┘

多过程+多线程模式(复杂度最高):

┌──────────┐┌──────────┐┌──────────┐│Process   ││Process   ││Process   ││┌────────┐││┌────────┐││┌────────┐│││ Thread ││││ Thread ││││ Thread │││└────────┘││└────────┘││└────────┘││┌────────┐││┌────────┐││┌────────┐│││ Thread ││││ Thread ││││ Thread │││└────────┘││└────────┘││└────────┘│└──────────┘└──────────┘└──────────┘

过程 vs 线程

过程和线程是蕴含关系,然而多任务既能够由多过程实现,也能够由单过程内的多线程实现,还能够混合多过程+多线程。

具体采纳哪种形式,要思考到过程和线程的特点。

和多线程相比,多过程的毛病在于:

  • 创立过程比创立线程开销大,尤其是在Windows零碎上;
  • 过程间通信比线程间通信要慢,因为线程间通信就是读写同一个变量,速度很快。

而多过程的长处在于:

多过程稳定性比多线程高,因为在多过程的状况下,一个过程解体不会影响其余过程,而在多线程的状况下,任何一个线程解体会间接导致整个过程解体。

多线程

Java语言内置了多线程反对:一个Java程序实际上是一个JVM过程,JVM过程用一个主线程来执行main()办法,在main()办法外部,咱们又能够启动多个线程。此外,JVM还有负责垃圾回收的其余工作线程等。

因而,对于大多数Java程序来说,咱们说多任务,实际上是说如何应用多线程实现多任务。

和单线程相比,多线程编程的特点在于:多线程常常须要读写共享数据,并且须要同步。例如,播放电影时,就必须由一个线程播放视频,另一个线程播放音频,两个线程须要协调运行,否则画面和声音就不同步。因而,多线程编程的复杂度高,调试更艰难。

Java多线程编程的特点又在于:

  • 多线程模型是Java程序最根本的并发模型;
  • 后续读写网络、数据库、Web开发等都依赖Java多线程模型。

因而,必须把握Java多线程编程能力持续深刻学习其余内容。

创立新线程

Java语言内置了多线程反对。当Java程序启动的时候,实际上是启动了一个JVM过程,而后,JVM启动主线程来执行main()办法。在main()办法中,咱们又能够启动其余线程。

要创立一个新线程非常容易,咱们须要实例化一个Thread实例,而后调用它的start()办法:

public class Main {    public static void main(String[] args) {        Thread t = new Thread();        t.start(); // 启动新线程    }}

然而这个线程启动后实际上什么也不做就立即完结了。咱们心愿新线程能执行指定的代码,有以下几种办法:

办法一:从Thread派生一个自定义类,而后覆写run()办法:

public class Main {    public static void main(String[] args) {        Thread t = new MyThread();        t.start(); // 启动新线程    }}class MyThread extends Thread {    @Override    public void run() {        System.out.println("start new thread!");    }}

执行上述代码,留神到start()办法会在外部主动调用实例的run()办法。

办法二:创立Thread实例时,传入一个Runnable实例:

public class Main {    public static void main(String[] args) {        Thread t = new Thread(new MyRunnable());        t.start(); // 启动新线程    }}class MyRunnable implements Runnable {    @Override    public void run() {        System.out.println("start new thread!");    }}

或者用Java8引入的lambda语法进一步简写为:

public class Main {    public static void main(String[] args) {        Thread t = new Thread(() -> {            System.out.println("start new thread!");        });        t.start(); // 启动新线程    }}

小结

Java用Thread对象示意一个线程,通过调用start()启动一个新线程;

一个线程对象只能调用一次start()办法;

线程的执行代码写在run()办法中;

线程调度由操作系统决定,程序自身无奈决定调度程序;

Thread.sleep()能够把以后线程暂停一段时间。

线程的状态

在Java程序中,一个线程对象只能调用一次start()办法启动新线程,并在新线程中执行run()办法。一旦run()办法执行结束,线程就完结了。因而,Java线程的状态有以下几种:

  • New:新创建的线程,尚未执行;
  • Runnable:运行中的线程,正在执行run()办法的Java代码;
  • Blocked:运行中的线程,因为某些操作被阻塞而挂起;
  • Waiting:运行中的线程,因为某些操作在期待中;
  • Timed Waiting:运行中的线程,因为执行sleep()办法正在计时期待;
  • Terminated:线程已终止,因为run()办法执行结束。

Maven根底

Maven是一个Java项目管理和构建工具,它能够定义我的项目构造、我的项目依赖,并应用对立的形式进行自动化构建,是Java我的项目不可短少的工具。