关键词:
使用线程更好的提高资源利用率,但也会带来上下文切换的消耗,频繁的内核态和用户态的切换消耗,如果代码设计不好,可能弊大于利。
一、线程
进程是分配资源的最小单位,线程是程序执行的最小单位;线程是依附于进程的,一个进程可以生成多个线程,这些线程拥有共享的进程资源;
二、线程生命周期(相关API)
1、5个阶段6种状态
5个阶段:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)。
6种状态:
public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }
1.1、新建--NEW
New并初始化。
四种方式:
(1)继承Thread类
package test; public class MyThread extends Thread{ @Override public void run() { System.out.println("MyThread is running..."); } } package test; public class Main { public static void main(String[] args){ new MyThread().start();//创建并启动线程 MyThread is running... } }
(2)实现Runnable接口
package test; public class MyThread implements Runnable{ @Override public void run() { System.out.println("MyThread is running..."); } } package test; public class Main { public static void main(String[] args){ Thread thread=new Thread(new MyThread()); thread.start();//MyThread is running... //或者new Thread(new MyThread()).start(); } }
(3)实现Callable接口
和Runnable接口不一样,Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能要强大,可以有返回值,可以声明抛出异常
Java5提供了Future接口来代表Callable接口里call()方法的返回值:
类FutureTask既实现了Future接口和Runnable接口,因此可以作为Thread类的target。
在Future接口定义了几个公共方法来控制它关联的Callable任务。
>boolean cancel(boolean mayInterruptIfRunning):试图取消该Future里面关联的Callable任务 >V get():返回Callable里call()方法的返回值,调用这个方法会导致程序阻塞,必须等到子线程结束后才会得到返回值 >V get(long timeout,TimeUnit unit):返回Callable里call()方法的返回值,最多阻塞timeout时间,经过指定时间没有返回抛出TimeoutException >boolean isDone():若Callable任务完成,返回True >boolean isCancelled():如果在Callable任务正常完成前被取消,返回True
举例:
package test; import jdk.nashorn.internal.codegen.CompilerConstants; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { //1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。 //2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值 FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>(){ @Override public Integer call() throws Exception{ System.out.println("FutureTask1 call ..."); return 100; } }); //从jdk1.8开始可以使用Lambda表达式创建Callable对象 FutureTask<Integer> task2 = new FutureTask<Integer>((Callable<Integer>)()->{ System.out.println("FutureTask2 call ..."); return 200; }); //3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口) new Thread(task,"有返回值的线程task").start();//实质上还是以Callable对象来创建并启动线程 new Thread(task2,"有返回值的线程task").start();//实质上还是以Callable对象来创建并启动线程 try { //4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值 System.out.println("子线程的返回值:" + task.get());//子线程的返回值:100 System.out.println("子线程的返回值:" + task2.get());//子线程的返回值:200 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
(4)使用线程池
1.2 就绪--Runnable
当线程对象调用了start()方法之后,该线程处于就绪状态,JVM会为其创建方法调用栈和程序计数器,等待系统为其分配CPU时间片。
调用start()方法与run()方法,对比如下:
(1)调用start()方法来启动线程,系统会把该run()方法当成线程执行体来处理。但如果直接调用线程对象的run()方法,则run()方法立即就会被执行,而且在run()方法返回之前其他线程无法并发执行。也就是说,系统把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程执行体;
(2)调用了线程的run()方法之后,该线程已经不再处于新建状态,不要再次调用线程对象的start()方法。只能对处于新建状态的线程调用start()方法,否则将引发IllegaIThreadStateExccption异常;
1.3 运行--Running
线程获得了CPU时间片才得以真正开始执行run()方法的线程执行体
1.4 阻塞--Blocked
处于运行状态的线程在某些情况下,让出CPU并暂时停止自己的运行,进入阻塞状态。
阻塞状态分类:
等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程占用),它会进入到同步阻塞状态;
其他阻塞:通过调用线程的sleep()或join()或发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕 时,线程重新转入就绪状态;
(1)WAITING:等待状态
线程处于 无限制等待状态,等待一个特殊的事件来重新唤醒,如:
通过wait()方法进行等待的线程等待一个notify()或者notifyAll()方法;
通过join()方法进行等待的线程等待目标线程运行结束而唤醒;
(2)TIMED_WAITING:时限等待状态
线程进入了一个 时限等待状态,如:sleep(3000),等待3秒后线程重新进行 就绪(RUNNABLE)状态 继续运行。
1.5 死亡--Dead
线程会以如下3种方式结束,结束后就处于死亡状态:
(1)run()或call()方法执行完成,线程正常结束;
(2)线程抛出一个未捕获的Exception或Error;
(3)直接调用该线程stop()方法来结束该线程—该方法不安全,通常不推荐使用;
终止(TERMINATED)状态,线程执行完毕后,进入终止(TERMINATED)状态。
package test; public class ThreadTest { public static void main(String[] args) throws InterruptedException { Runnable interruptTask = new Runnable() { int i = 0; @Override public void run() { try { //在正常运行任务时,经常进行本线程的中断标志,如果被设置了终端标志就自行停止线程 while (!Thread.currentThread().isInterrupted()){ //休眠100ms Thread.sleep(100); i++; System.out.println(Thread.currentThread().getName() + " 状态(" + Thread.currentThread().getState() + ") loop " + i); } }catch (InterruptedException e){ //在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。) System.out.println(Thread.currentThread().getName() + " 状态(" + Thread.currentThread().getState() + ") catch InterruptedException."); } } }; Thread t1 = new Thread(interruptTask,"t1"); System.out.println(t1.getName() +" 状态("+t1.getState()+") is new."); // 启动“线程t1” t1.start(); System.out.println(t1.getName() +" 状态("+t1.getState()+") is started."); // 主线程休眠300ms,然后主线程给t1发“中断”指令。 Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" 状态("+t1.getState()+") is interrupted."); // 主线程休眠300ms,然后查看t1的状态。 Thread.sleep(300); System.out.println(t1.getName() +" 状态("+t1.getState()+") is interrupted now."); } }
结果:
t1 状态(NEW) is new. t1 状态(RUNNABLE) is started. t1 状态(RUNNABLE) loop 1 t1 状态(RUNNABLE) loop 2 t1 状态(TIMED_WAITING) is interrupted. t1 状态(RUNNABLE) catch InterruptedException. t1 状态(TERMINATED) is interrupted now.
java并发专题之十juc-locks之线程池框架概述
环境 jdkversion:jdk1.8.0_171一、Executor接口执行器接口,也是最顶层的抽象核心接口,分离了任务和任务的执行。二、ExecutorService接口在Executor的基础上提供了执行器生命周期管理,任务异步执行等功能。在Executor的基础上增强了... 查看详情
java高并发专题之8线程组
线程组我们可以把线程归属到某个线程组中,线程组可以包含多个线程以及线程组,线程和线程组组成了父子关系,是个树形结构,如下图:使用线程组可以方便管理线程,线程组提供了一些方法方便方便我们管理线程。创建线... 查看详情
java面试系列之并发编程专题-java线程池灵魂拷问
...nized相关的知识,可以点击链接查看详情:Java面试系列之并发编程专题- 查看详情
蚂蚁java互联网高级架构师第3期视频教程
...:百度网盘下载目录├─0001-3期-开班仪式.rar├─0002-3期-并发编程专题之多线程基础.rar1?3G6n-E"d3C%w├─0003-3期-并发编程专题之Java内存模型.rar├─0004-3期-并发编程专题-多线程之间通讯.rar├─0005-3期-并发编程专题-线程池原理分... 查看详情
并发编程专题-线程的创建方式
1.创建多线程几种方式1.1继承Thread,重写父类的run()方法Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行... 查看详情
java并发专题之三java线程同步
从JDK5引入CAS原子操作,但没有对synchronized关键字做优化,而是增加了J.U.C.concurrent,concurrent包有更好的性能;从JDK6对synchronized的实现机制进行了较大调整,包括使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除... 查看详情
并发编程专题-线程的创建方式(代码片段)
1.创建多线程几种方式1.1继承Thread,重写父类的run()方法Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。... 查看详情
java面试系列之并发编程专题-java线程池灵魂拷问
...nized相关的知识,可以点击链接查看详情:Java面试系列之并发编程专题-Synchronized灵魂拷问下面我们开撸!值得一提的是,以下内容来自程序员实战基地fightjava.com一位网友最近的面试场景,笔者尝试着将其复现,其中有些是笔者... 查看详情
java并发编程专题系列之深入分析synchronized(基础篇)
synchronized同步关键字简介synchronized是属于JVM层面的一个关键字,底层是通过一个monitor对象(管程对象)来完成,由于wait()/notify()等方法也依赖于monitor对象,所以只有在同步的块或者方法中才能调用wait/notify等方法synchronized同步代码... 查看详情
java并发编程系列之二十八:completionservice
CompletionService简介CompletionService与ExecutorService类似都可以用来执行线程池的任务,ExecutorService继承了Executor接口,而CompletionService则是一个接口,那么为什么CompletionService不直接继承Executor接口呢?主要是Executor的特性决定的,Executo... 查看详情
并发编程专题-线程的状态(代码片段)
1.线程状态Java中,线程的状态使用一个枚举类型来描述的。这个枚举一共有6个值:NEW(新建)、RUNNABLE(运行)、BLOCKED(锁池)、TIMED_WAITING(定时等待)、WAITING(等待)、TERMINATED(终止、结束)。但是大多数人的理解和上面的这六种还是有些差... 查看详情
java并发编程之二彻底理解java的wait和notify机制(代码片段)
简单介绍wait方法wait方法的作用是使当前执行代码的线程进行等待,它是Object类的方法,该方法用来将当前线程置入等待队列中,并且在wait所在的代码行处停止执行,直到接到通知或被中断为止。该方法只能在同... 查看详情
java多线程和并发基础面试问答(转载)
JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的... 查看详情
java多线程和并发基础
...kaj 译文出处:ifeve-郑旭东 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到... 查看详情
java多线程和并发基础面试问答(转载)
... JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在... 查看详情
java基础-多线程基础
并发并发在单核和多核CPU上都存在,对于单核CPU,通过轮训时间片的方式实现并发.线程线程对象利用Thread对象,有两种方式来创建并发程序:直接创建并管理线程.当程序要启动一个异步任务的时候,直接创建一个线程.将线程管理抽象... 查看详情
大厂java核心面试知识点整理,二十九个专题任你挑,美滋滋~
...在一起并分享出来,内容涵盖了JVM、Java集合、Java多线程并发、Java基础、spring原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、Java算法、数据结... 查看详情
java多线程和并发基础面试问答
...i-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到... 查看详情