线程与过程

概念

过程:过程指的是一段正在运行的程序
线程:一个程序运行中能够执行多个工作,工作就称之为线程。
过程能够有多个线程,各个线程之间共享程序的内存空间

为什么有了过程,还会呈现线程?

每个过程有本人独立的地址空间,多并发申请,为每一个申请创立一个过程,导致系统开销、用户申请效率低

区别

每个过程有用本人独有的变量,线程共享数据,线程之间的通信相比于过程之间的通信更加无效,更加容易
线程相比于过程创立/销毁开销 更小
过程是资源分配的最小单位,线程是CPU调度的最小单位
多过程程序更加强壮,多线程程序只有有一个线程挂掉,对其共享资源的其余线程也回产生影响
如果谋求速度,谋求零碎稳固抉择线程;如果频繁的创立和销毁,抉择线程;

线程的创立

说完线程的基本知识,那么久要谈谈在利用中,咱们应该如何创立线程,理论利用中创立线程次要有以下四种办法,如下:

办法一:继承Thread类,重写run()办法

class  MyThread extends  Thread{    @Override    public void run() {        while(true){            System.out.println("eat food");        }    }}public class TestDemo1 {    public static void main(String[] args) {        //边吃饭边看电视        //创立子线程对象        Thread thread = new MyThread();        //启动吃饭的thread         thread.run();         //main线程        while(true){            System.out.println("watch Tv");        }    }  }

办法二:实现Runable接口

class  MyRunnable implements  Runnable{    @Override    public void run() {        while(true){            System.out.println("eat food");        }    }}public class TestDemo1 {    public static void main(String[] args) {    //实现runnable接口 创立子线程  创立子线程对象        Thread thread = new Thread(new MyRunnable());        thread.start();    }  }

办法三:匿名线程 应用匿名外部类

  //匿名外部类   创立线程            new Thread(){                @Override                public void run() {                 System.out.println("thread 0");                }            }.start();

办法四:实现Callable接口,重写call()办法

利用Callable创立时,步骤较为简单,具体如下:
a.创立Callable接口的实现类,重写call办法
b.创立Callable实现类的实例,应用FutureTask包装该实例
c.将FutureTask实例作为参数创立线程对象
d.启动该线程
e.调用FutureTask的get办法获取子线程的执行后果

class MyCallable implements Callable<Integer>{    @Override    public Integer call() throws Exception {        int sum = 0;        for(int i=0; i<10000; i++){            sum += i;        }        return sum;    }}public class TestDemo1 {    public static void main(String[] args) {     //创立Callable接口的实现类    重写call 办法        //创立Callable实现类的实例        Callable<Integer> callableTask = new MyCallable();        //应用FutureTask包装实例        FutureTask<Integer> task = new FutureTask<>(callableTask);        //Future实例作为参数创立线程对象        Thread thread = new Thread(task);        //启动该线程        thread.start();        //调用FutureTask的get 办法获取子线程的执行后果        try {            Integer integer = task.get();            System.out.println("result"+integer);        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }

可能有人会思考,这里同样应用Runable和Callable接口来创立线程,那么这两者各有什么不同呢?能想到这,堪称是很用心啦,这也是这里的一个面试考点呐!!!
Runable 接口和 Callable 接口的区别?

这里就简略说一下两者的区别,然而仅仅独自比拟两个接口的区别实际意义并不大,并且也不是很全面,之后会
具体的剖析两个接口的区别,在更深层次下来了解两个接口。大家持续关注吖!

线程的生命周期及罕用办法解析

生命周期

线程的生命周期次要包含以下六种状态:新建状态、就绪状态、阻塞状态、期待状态、睡眠状态、终止状态。

  1、new() :新建状态  new关键字创立一个线程对象,它并不是出于执行状态 并未执行START办法启动线程  2、runnable() :就绪状态   期待被执行  线程对象调用START办法,才是JVM中真正创立了一个线程,  创立好的线程并不是一经启动,就会立刻执行。该状态的所有线程会位于就绪线程池中,期待以后操作系统的资源,例如CPU,  取得CPU的使用权。  3、blocked(): 阻塞状态 期待一个监视器锁进入同步代码块或者同步办法,代码块和办法指某一时刻  只可能有一个线程去执行,其余线程只能期待。  4、Waiting(): 期待状态  Object.wait()/Thread.join()/LockSupport.park() 都会使得以后从Runnable  转换为Waiting 状态    调用waiting()  会开释monitor Lock  5、TimeWaiting():睡眠状态       调用Object.wait(long miles)/Thread.sleep(long miles)/LockSupport.parkNano()/LockSupport.parkUntile()  6、Terminated():终止状态  是一个线程的最终状态  线程如果进入此状态,意味着该线程完结。

简略理解线程的生命周期之后,那咱们持续学习线程六状态之间的转换:

罕用办法解析

1) start()

启动一个线程,将线程增加到线程组中,线程状态会从New 状态转换到Runnable 状态,而后获取CPU之后进入Running状态执行run();

2)sleep()

静态方法 ,存在两个重载函数

 public static native void sleep(long millis) public static void sleep(long millis, int nanos)

作用:sleep()办法使得以后线程进入睡眠状态并指定休眠工夫,暂停执行;
sleep()办法不会开释Monitor Lock 使用权;
JDK1.5之后,引入枚举类TimeUnit ,其对sleep进行封装 间接应用从而省去工夫换算的步骤,不必将工夫转为ms,更加的方便使用。

3)yield()

public static native void yield();

作用: 揭示CPU调度器 ,我以后的线程违心放弃以后的CPU资源(属于启发式办法),如果以后CPU资源不缓和,会疏忽这种揭示。
yield()办法不会开释Monitor Lock 使用权;

4)join()

join() 始终期待join(long millis) 期待指定毫秒数join(long millis, int nanos) 期待指定毫秒数

含意:在线程B中join某个线程A,会使得B线程进入期待,直到线程A完结生命周期,或者达到给定的工夫,在这给定工夫期间线程B会处于期待状态.

5)wait()

调用某个对象的wait()办法能够让以后线程阻塞

6)notify()

调用以后对象notify/notifyAll才可能唤醒这个对象所在的线程。

7)notifyAll()

将锁对象期待池中所有线程挪动到锁标记期待池中。
留神:应用这三个办法须要让以后线程领有以后对象的monitor lock

8)线程中断办法

每个Java线程都会有一个中断状态位,程序能够检测这个中断状态位判读线程是否执行完结。有以下三种办法:
interrupt()
public void interrupt() 由线程对象调用,将中断地位置为true

public void interrupt();

如下办法可能使得以后线程进入阻塞状态,调用interrupt办法能够打断阻塞,因而这种办法被称之为可中断办法

Object.wait()/wait(long)Thread.sleep(long)/TimUnit.XXX.sleep(long)Thread.join()/Thread.join(long)

如果一个线程被interrupt,设置interrupt flag;如果以后线程正在执行可中断办法,调用interrupt办法,反而导致interrupt flag被革除.

isInterrupted

public boolean isInterrupted();

实例办法,判断以后线程的中断状态位是否为true,判断过程是否被中断。

interrupted()

public static boolean interrupted();

静态方法,调用interrupted会擦除中断状态位的标识,判断过程是否被中断

interrupted和isInterrupted办法的区别:

1)interrupted()是静态方法,isInterrupted()是实例办法;
2)interrupted()会清空线程中断状态,isInterrupted()不会清空线程中断状态。

最初

欢送关注公众号:前程有光,支付一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java外围知识点总结! 这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java汇合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。