Java多线程

JAVA_HOME

JAVA_HOME=C:\Program Files\Java\jdk1.8.0_131
Path=%JAVA_HOME%\bin
language-java复制代码

第一章 线程简介

1.1 进程 Process

进程是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。

1.2 线程 Thread

通过在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位。

1.3 核心概念

  1. 线程就是独立的执行路径;
  2. 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  3. main()称之为主线程,为系统的入口,用于执行整个程序;
  4. 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的;
  5. 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  6. 线程会带来额外的开销,如cpu调度时间,并发控制开销;
  7. 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

第二章 线程实现(重点)

2.1 继承Thread类(重点)

  1. 自定义线程类继承Thead类
  2. 重写run()方法,编写线程执行体;
  3. 创建线程对象,调用start()方法启动线程,(调用run方法)。

注意:线程开启不一定立即执行,有cpu调度执行。

2.2 实现Runnable接口(重点)

  1. 自定义线程类实现Runnable接口;
  2. 重写runn方法;
  3. 执行线程需要丢入runnable接口实现类,调用start方法。

2.3 实现Callable接口(了解)

  1. 实现Callable接口,需要返回值类型;
  2. 重写call方法,需要抛出异常;
  3. 创建目标对象;
  4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  5. 提交执行:Future result1 = se.submit(t1);
  6. 获取结果:boolean r1 = result1.get();
  7. 关闭服务:ser.shutdownNow();

第三章 线程状态

3.1 概述

  1. 线程状态图1
    创建状态、就绪状态、阻塞状态、运行状态、死亡状态
  2. 线程状态图2
    new、就绪状态、运行状态、阻塞状态、dead

3.2 线程方法

3.2.1 线程停止

3.2.2 线程休眠(sleep)

  1. sleep(时间)指定当前线程阻塞的毫秒数;
  2. sleep存在异常InterruptedException;
  3. sleep时间达到后线程进入就绪状态;
  4. sleep可以模拟网络延时,倒计时等;
  5. 每一个对象都有一个锁, sleep不会释放锁;

3.2.3 线程礼让(yield)

  1. 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  2. 将线程从过年运行状态转为就绪状态;
  3. 让cpu重新调度,礼让不一定成功!看CPU心情

3.2.4 Join

  1. Joio合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞;
  2. 可以想象成插队

3.2.5 线程状态观测(Thread.State)

  1. NEW 尚位启动的线程处于此状态;
  2. RUNNABLE 在Java虚拟机中执行的线程处于此状态;
  3. BLOCKED 被阻塞等待监视器锁定的线程处于此状态;
  4. WAITING 正在等待另一个线程执行待定动作的线程处于此状态;
  5. TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态;
  6. TERMINATED 已退出的线程处于此状态。
  7. 一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。

3.2.6 线程优先级

  1. Java提供一个线程调度来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
  2. 线程的优先级用数字表示,范围从1~10
    • Thread.MIN_PRIORITY = 1;
    • Thread.MAX_PRIORITY = 10;
    • Thread.NORM_PRIORITY = 5;
  3. 使用以下方式改变或获取优先级
    • getPriority() setPriority(int xxx)

###3.2.7 守护(daemon)线程

  1. 线程分为用户线程守护线程
  2. 虚拟机必须确保用户线程(main)执行完毕
  3. 虚拟机不用等待守护线程(gc)执行完毕
  4. 如,后台记录操作日志,监控内存,垃圾回收等待

第四章 线程同步(重点)

  1. 多个线程操作同一个资源
  2. 现实生活中,我们会遇到”同一个资源,多个人都想使用”的问题,比如,食堂排队打饭,每个人都想吃饭,最天然的解决方法就是,排队,一个个来;
  3. 处理多线程问题时,多线程访问同一个对象,并且某些线程还想修改这个对象。这个时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。
  4. 队列和锁:**每个对象都有一把锁。**队列+锁才可以保证线程的安全性。

4.1 线程同步

  1. 由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,使用后释放锁即可,存在以下问题:
    • 一个线程持有锁会导致其他所有需要此锁的线程挂起;
    • 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
    • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题。

4.2 同步方法

  1. 由于我们可以通过private关键字来保证数据对象只能被方法访问,所有我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种方法:synchaonized方法和synchronized快同步方法:public synchronized void method(int ages){}
  2. synchronized方法控制对“对象“的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行缺陷:若将一个大的方法申明为synchronized将会影响效率

4.3 同步块

  1. 同步快:synchronized(Obj){}
  2. Obj称之为同步监视器
    • Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
    • 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this, 就是这个对象本身,活着是class[反射中讲解]
  3. 同步监视器的执行过程
    • 第一个线程访问,锁定同步监视器,执行其中代码;
    • 第二个线程访问,发现同步监视器被锁定,无法访问;
    • 第一个线程访问完毕,解锁同步监视器;
    • 第二个线程访问,发现同步监视器没有锁,然后锁定并访问。

4.4 死锁

  1. 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有“两个以上对象的锁“时,就可能会发生“死锁“的问题。

4.5 死锁的避免方法

产生死锁的四个必要条件

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

4.6Lock(锁)

  1. 从JDK5.0开始,Java提供了更强大的线程同步机制–通过显示定义锁对象来实现同步。同步锁使用Lock对象充当。
  2. Java.util.concurrenrt.locks.Lock接口是控制多个线程

4.4 并发

同一个对象被多个线程操作


第五章 线程通信问题


第六章 高级主题


Java Util

本周周一
LocalDateTime nowMonday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(DayOfWeek.MONDAY);
上周周一
LocalDateTime lastMonday = LocalDateTime.of(LocalDate.now(),LocalTime.MIN).minusWeeks(1).with(DayOfWeek.MONDAY);


计算时间差
 LocalDateTime startTime = LocalDateTime.now().plusDays(-7);
 LocalDateTime endTime = LocalDateTime.now();

 Duration duration = Duration.between(startTime, endTime);
 duration.toDays();  // 获取相差天数
 duration.toMillis();
language-java复制代码

第一章 对象导论

1.1 抽象过程

我们将问题空间中的元素及其在解空间中的表示称为“对象“。(你还需要一些无法类比为问题空间元素的对象。)这种思想的实质是:程序可以通过添加新类型的对象使自身适用于某个特定问题。

  1. 万物皆为对象。
  2. 程序是对象的集合,它们通过发送消息来告知彼此所要做的。
  3. 每个对象都有自己的由其他对于所构成的存储。
  4. 每个对象都拥有其类型。
  5. 某一特定类型的所有对象都可以接收同样的消息。

1.2 每个对象都有一个接口

1.3 每个对象都提供服务

1.4 被隐藏的具体实现

1.5 复用具体实现

1.6 继承

1.7 伴随多态的可交互换对象

1.8 单根继承结构

1.9 容器

1.10 对象的创建和生命期

1.11 异常处理:处理错误

1.12 并发编程

  1. 在计算机编程中有一个基本概念,就是在同一时刻处理多个任务的思想。许多程序设计问题都要求,程序能够停下正在做的工作,转而处理某个其他问题,然后再返回主进程。有许多方法可以实现这个目的。最初,程序员们用所掌握的有关机器底层的知识来编写中断服务程序,主进程的挂起是通过硬件中断来触发的。尽管这样做可以解决问题,但是其难度太大,而且不能移植,所以使得将程序移植到新型号的机器上时,即费时又费力。
  2. 又是中断对于处理时间性强的任务是必需的,但是对于大量的其他问题,我们只是想把问题切分成多个可独立运行的部分(任务),从而提高程序的响应能力。在程序中,这些彼此独立运行的部分称之为线程,上述概念被成为“并发“。并发最常见的例子就是用户界面。通过使用任务,用户可以在掀起揿下按钮后快速得到一个响应,而不用被迫等待到程序完成当前任务为止。
  3. 通常,线程只是一种为单一处理器分配执行时间的手段。但是如果操作系统支持多处理器,那么每个任务都可以被指派给不同的处理器,并且它们是在真正地并行执行。在语言级别上,多线程所带来的便利之一便是程序员不用再操心机器上是有多个处理器还是只有一个处理器。由于程序在逻辑上被分为线程,所以如果机器拥有多个处理器,那么程序不需要特殊调整也能执行得更快。
  4. 所有这些都使得并发看起来相当简单,但是有一个隐患:共享资源。如果有多个并行任务都要访问同一项资源,那么就会出问题。例如,两个进程不能同时向一台打印机发送信息。为了解决这个问题,可以共享的资源,例如打印机,必须在使用期间被锁定。因此,整个过程是:某个任务锁定某项资源,完成其任务,然后释放资源锁,使其他任务可以使用这项资源。
  5. Java的并发是内置于语言中的,Java SE5已经增添来大量格外的库支持。

1.13 Java与Internet

1.14 总结



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 hjxstart@126.com