Java多线程 1.认识Java多线程

1.Java多线程-认识Java线程

2.Java多线程-线程安全

3.Java多线程-线程协作

4.Java多线程-线程池

5.Java多线程-栅栏

6.Java多线程-Fork/Join

 


 

1.1 什么是多线程

 1.1.1 计算机硬件

计算机的核心硬件有磁盘、内存、CPU,磁盘用来持久化保存数据,CPU用于计算,内存是磁盘和CPU之间的一个缓冲区。

说明:

  1. 磁盘读写太慢,CPU运算太快,如果CPU每次都到磁盘读写数据效率很低,所以有了读写速度更快的内存,将CPU频繁使用的数据读取到内存供CPU使用,等CPU使用完再一次性写到磁盘;

  2. 单就CPU处理器来说,目前计算机配置有多处理器和多核处理器,多处理器指电脑有多个处理器,每个是单核的;多核处理器是电脑有一个处理器,但是是多核;区别在于处理器之间通信方式不一样,多处理器之间需要通过主板总线通信,多核处理器通过处理器内部总线通信;每个处理器或每一个核可以运行一个线程;

  3.在CPU内部有一块速度更快的缓存,用来加载内存中的数据,供CPU使用;

 1.1.2 应用程序、进程、线程

操作系统可以同时运行多个应用程序(例如听着音乐写博客),一个应用程序对应一个进程,每个进程都有一个主线程同进程共生死;

操作系统会给启动的应用程序分配一块独立的内存空间,其他应用程序不能访问;

CPU的使用权限会在不同的进程之间高速切换,获得CPU使用权的进程就可以执行应用程序的功能(例如暂停播放音乐);

当一个应用程序需要同时做多件事情的时候,只有一个主线程就不够用了,例如音乐播放器的播放音乐和滚动歌词,这是2个需要同时进行的任务,需要有2个线程驱动,当应用程序获得CPU使用权时,CPU在各个线程之间高速切换,使不同线程驱动的任务同时运行。

说明:

  1.应用程序和进程一一对应,在本文中可以看做一个概念;

  2.一个应用程序对应一个进程,每个进程至少有一个主线程(还可以有其他子线程),应用程序的功能是在线程驱动的任务中定义的;

  3.操作系统会给每个应用程序分配一块独立的内存,其他应用程序不能访问,但是此内存在当前应用程序的不同线程之间是可以共享的;

1.2 Java线程

应用程序的功能是在线程中实现的,在Java中线程和任务密不可分,功能定义在任务中,线程驱动任务执行;

线程和任务的关系就像火箭和卫星的关系,火箭用来发射卫星,具体的太空拍照、通信都是卫星所有的功能;

Java提供的线程类是Thread,任务提供了2个接口Runnable和Callable(JDK的这2个名字很不好),一般情况都是将任务接口的实现类提交给线程,让线程驱动任务执行;

现在开始针对一个Java程序描述Java的线程,可以忘掉应用程序、进程,就看做CPU使用权只在Java程序的不同线程之间高速切换;

 1.2.1 Java线程的五种状态

  1. 新建状态

通过Thread thread = new Thread(new Runnable())新建一个线程,线程进入新建状态

  2. 可运行状态

    • 来自新建状态:执行thread.start()方法
    • 来自阻塞状态:满足结束阻塞的条件
    • 来自运行状态:执行Thread.yield()方法 或 分配的CPU时间片结束

  3. 运行状态

    线程在可运行线程池中被选中执行

  4. 阻塞状态

    • 同步阻塞:线程获取锁失败导致线程进入同步阻塞状态
    • 等待阻塞:执行wait()方法线程进入等待阻塞
    • 其他阻塞:sleep()休眠、join联合、IO阻塞等

  5. 死亡状态

    线程驱动的任务执行完毕或产生异常

 1.2.2 Java线程的创建方式

  1. 继承Thread

    继承Thread,复写run方法,在run方法中实现功能; (Thread类实现了Runnable接口)

 1 public class ThreadCreate
 2 {
 3     public static void main(String[] args)
 4     {
 5         //匿名类+匿名对象
 6         new Thread("Thread 子类线程")
 7         {
 8             @Override
 9             public void run()
10             {
11                 System.out.println("Thread"+Thread.currentThread().getName());
12             }
13         }.start();
14     }
15 }

2. 实现Runnable

 Runnable定义任务,Runnablle的实现类作为Thread类的参数

 1 public class ThreadCreate
 2 {
 3     public static void main(String[] args)
 4     {
 5         //定义任务有3种写法:1.定义Runnable实现类;2.使用匿名类;3.Runnable是一个函数接口,可以使用lambda表达式
 6         //使用匿名类
 7         new Thread(new Runnable() {
 8             @Override
 9             public void run() {
10                 System.out.println("Thread:"+Thread.currentThread().getName());
11             }
12         },"Runnable定义功能,Thread驱动").start();
13     }
14 }

3. 实现Callable

Callable定义任务,提交给线程池执行,Thread类不能直接驱动Callable任务,需要提交给线程池执行

 1 import java.util.concurrent.Executors;
 2 import java.util.concurrent.Future;
 3 
 4 public class ThreadCreate
 5 {
 6     public static void main(String[] args) throws Exception {
 7         //定义任务有3种写法:1.定义Callable实现类;2.使用匿名类;3.Callable是一个函数接口,可以使用lambda表达式
 8         //使用lambda表达式
 9         Future<String> result = Executors.newCachedThreadPool().submit(() -> {
10             //因为线程是在线程池中定义的,所以线程的名字需要在创建线程池的时候指定
11             System.out.println(Thread.currentThread().getName());
12             return "Callable定义任务,线程池驱动";
13         });
14         System.out.println("Thread:"+result.get());
15     }
16 }

1.3 Java多线程

  提高CPU的使用效率;例如,程序读取大文件时耗时较长但不需要CPU,此时可以让出CPU使用,让CPU做一些其他线程需要的计算;

  在多处理器或者多核处理器的计算机上使用多线程更有意义;

  与多线程相关的几个概念:同步/异步、阻塞/非阻塞、并发/并行, 通过应用程序读取3个文件内容在页面显示来说明

 1.3.1 同步和异步

  同步:应用程序读先取文件1,读取完毕后再读取文件2

  异步:应用程序同时读取文件1和文件2

 说明:

  1. 通过查看应用程序在执行某一任务的时候,其他任务是否停止来判定同步或异步;

  2. 在Java中通过多线程实现异步;

  3. Java通过锁(synchronized和Lock)来实现多线程中的同步;

 1.3.2 阻塞和非阻塞

  阻塞:应用程序读取文件3,发现内容为空,则一直等待,直到有内容后再返回;

  非阻塞:应用程序读取文件3,发现内容为空,则直接返回;

说明:

  1. 在Java中阻塞和非阻塞一般指方法调用,当不满足方法执行的条件时,方法是立即返回(非阻塞)还是等待(阻塞);

  2. 前端http请求的同步和异步,和这里的阻塞和非阻塞意思相近;

  3.阻塞/非阻塞 和 同步/异步是完全不同的概念,阻塞/非阻塞发生在一个线程中的方法调用;

 1.3.2 并发和并行

  并发:应用程序在读取文件内容的同时,也在向显示页面返回数据;

  并行:同异步,应用程序同时读取文件1和文件2;

说明:

  1. 并发是应用程序同时在做不同的事情(读取文件和显示数据),并行是应用程序同时做相同的事情(都是读取文件);

posted @ 2018-07-03 22:43  kepus  阅读(454)  评论(0编辑  收藏  举报