日期与工夫
Date和Calendar
计算机示意的工夫是以整数示意的工夫戳存储的,即Epoch Time,Java应用long
型来示意以毫秒为单位的工夫戳,通过System.currentTimeMillis()
获取以后工夫戳。
Java有两套日期和工夫的API:
- 旧的Date、Calendar和TimeZone;
- 新的LocalDateTime、ZonedDateTime、ZoneId等。
别离位于java.util
和java.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()
返回的年份必须加上1900
,getMonth()
返回的月份是0
~11
别离示意1~12月,所以要加1,而getDate()
返回的日期范畴是1
~31
,又不能加1。
打印本地时区示意的日期和工夫时,不同的计算机可能会有不同的后果。如果咱们想要针对用户的偏好准确地管制日期和工夫的格局,就能够应用SimpleDateFormat
对一个Date
进行转换。
Calendar
Calendar
能够用于获取并设置年、月、日、时、分、秒,它和Date
比,次要多了一个能够做简略的日期和工夫运算的性能。
LocalDateTime
从Java 8开始,java.time
包提供了新的日期和工夫API,次要波及的类型有:
- 本地日期和工夫:
LocalDateTime
,LocalDate
,LocalTime
; - 带时区的日期和工夫:
ZonedDateTime
; - 时刻:
Instant
; - 时区:
ZoneId
,ZoneOffset
; - 工夫距离:
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我的项目不可短少的工具。