1、Java多线程基础

1、简介

一、操做系统

在早起的裸机时代,计算机很是地昂贵,并且也没有操做系统的概念,计算机从头至尾只能执行一个程序。若是程序在执行一个耗时的操做,那么在这个过程当中,计算机就有大量的资源闲置在那里,这是很是浪费的。html

而这个时候,操做系统的概念被提出了。在操做系统的控制下,一个计算机能够执行不少的程序。计算机的资源由操做系统进行分配,程序之间得到计算机资源并执行各自的任务,相互独立。操做系统的出现使得计算机资源的利用率大大增长。java

你也能够将操做系统理解为,运行程序的程序。类比AI是一种产生算法的算法。算法

二、进程和线程

操做系统能够执行多个程序,每一个程序在计算机中便是一个“进程”。进程的执行是并行的,实际上这里的“并行”并不彻底是物理意义上的并行。操做系统会给每一个进程分配必定的执行时间,而且CPU在这些进程之间快速地切换执行,从而近似地达到了一种并行执行的效果。固然,现代CPU也从早期的单核发展为4核、8核,能够从物理上同时执行。即便是单核,也可以控制多个执行流达到物理上并发的目的。编程

操做系统使得程序得以并发执行,但随着需求的增长,咱们但愿每一个程序也可以并发多个任务。因此,线程的概念就应运而生了。线程是依赖于进程的,共享进程的计算机资源。一个进程能够拥有一到多个线程。线程的并行执行和进程的理念是同样的,共享进程的时间片,快速地执行切换。api

三、Java多线程

Java编程语言为帮助开发者开发多线程的应用程序设计了一套简单的语义,你能够利用Java的内置支持来构建多线程程序,充分利用CPU资源,提升程序的响应速度多线程

2、Java线程的生命周期

下图,摘录自菜鸟教程:http://www.runoob.com/java/java-multithreading.html并发

这个图相信你们都很熟悉,它是表达了线程的生命周期,包含了几个状态,以下:异步

1)建立:当咱们在程序中new出来一个线程实例对象的时候,线程便处于建立状态;编程语言

2)就绪:当咱们调用了start()方法,表示该线程即将等待JVM的native方法去调用咱们的线程,也就是就绪状态;ide

3)运行:若是JVM调用了咱们的线程,线程实例执行中,它就处于运行状态;

4)阻塞:运行过程当中可能出现sleep、wait或者其它IO操做等,这个时候当前的线程就处于阻塞状态,让出CPU的资源,而不是继续占用。

5)死亡:若是线程正常执行完毕,手动退出或者意外结束,那么线程就进入了死亡状态,该线程占用的资源也会被自动回收。

3、使用示例

Java显示建立线程有两种实现:

1)继承Thread类

public class ThreadDemo extends Thread { @Override public void run() { System.out.println("执行了" + Thread.currentThread().getName()); } public static void main(String[] args) { new ThreadDemo().start(); System.out.println("主线程执行了" + Thread.currentThread().getName()); } }

事实上,Thread类实现了Runnable接口,而咱们重写了Runnable的run方法,当调用start()方法的时候,该线程会调用native方法,从而JVM会去异步执行线程实例的run方法。

2)实现了Runnable接口

public class RunnableDemo implements Runnable { @Override public void run() { System.out.println("线程执行" + Thread.currentThread().getName()); } public static void main(String[] args) { new Thread(new RunnableDemo()).start(); System.out.println("主线程执行" + Thread.currentThread().getName()); } }

实现Runnable接口的方式,也须要将Runnable做为Thread实例的构造入参,而后经过start()将线程转换为就绪状态。若是你直接调用run方法是不会异步运行的。

以上两种实现,其实都是基于Runnable接口和Thread类,只是写法不一样。

4、经常使用API

  1. currentThread():静态方法,返回当前线程的引用
  2. getId():返回当前线程的标识符
  3. getName():返回当前线程的引用
  4. getPriority():返回当前线程的优先级
  5. getState():返回当前线程的状态
  6. interrupt():中断线程(仅是打上中断标识,没法强制中止线程)
  7. interrupted():静态方法,返回是否中断
  8. isAlive():是否存活
  9. isDaemon():是否守护线程
  10. isInterrupted():是否中断
  11. yield():静态方法,暂停当前线程,执行其它线程
  12. start():使线程进入就绪状态
  13. sleep(long millis):静态方法,使线程休眠
  14. setPriority(int priority):设置优先级,优先级高的会先执行
  15. setName():设置名字
  16. setDaemon():设置为守护线程
  17. join():等待其它线程停止之后再继续执行
  18. wait():等待notify唤醒
  19. notify():唤醒wait线程

yield示例

yield执行的时候暂停当前线程执行,让出CPU资源,去执行其它线程

public class YieldDemo { private static volatile boolean isReady = false; public static void main(String[] args) throws InterruptedException { new Thread(() -> { System.out.println(Thread.currentThread().getName() + "让主线程执行"); while (!isReady) { Thread.yield(); } System.out.println(Thread.currentThread().getName() + "执行完毕"); }).start(); Thread.sleep(5000); isReady = true; System.out.println(Thread.currentThread().getName() + "执行完毕"); } }

join示例

join的做用是让将某个线程插入到当前线程的执行位置,并等待该线程执行完毕之后再执行当前线程。

public class JoinDemo { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + "开始执行"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行完毕"); }); thread.start(); System.out.println(Thread.currentThread().getName() + "等待子线程执行完毕"); thread.join(); System.out.println(Thread.currentThread().getName() + "执行完毕"); } }

notify/wait示例

notify和wait使用比较特殊,须要得到同步锁资源

notify和wait方法是Object对象的方法,任何对象都会有。它的做用是什么呢?咱们举一个场景示例:

1)存在两个线程A和B;

2)咱们但愿A执行完毕之后通知B去执行,而B在A通知以前一直等待

代码示例以下:

public class WaitDemo { private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 3; i++) { new Thread(() -> { // 要先得到同步锁
                synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " waiting"); // 等待notify
 lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } System.out.println("sleep"); Thread.sleep(5000); // 要先得到同步锁
        synchronized (lock) { System.out.println("notify"); // 执行notify
 lock.notifyAll(); System.out.println("finished"); } } }

这里随意创建了一个lock对象做为锁对象,子线程拿到这个锁之后执行等待。而主线程拿到锁之后,发送通知,执行结果以下:

sleep Thread-0 waiting Thread-1 waiting Thread-2 waiting notify finished Thread-2 end waiting Thread-1 end waiting Thread-0 end waiting

注意:若是notifyAll()在wait()以前执行了,那么子线程将无线等待下去,你能够给wait设置超时时间

更多API示例,参考JDK文档:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/Thread.html

相关文章
相关标签/搜索