Java面试--Java多线程并发(一)长文全解析

Java多线程并发

 

Table of Contents

1.Java并发知识库

2.Java线程实现/创建方式

2.1 继承Thread类。

2.2 实现Runnable接口

 

3.4种线程池

3.1 newCachedThreadPool

3.2 newFixedThreadPool

3.3 newScheduledThreadPool

3.4 newSingleThreadExcutor

4.线程生命周期

4.1 新建状态 New

4.2 就绪状态 Runnable

4.3 运行状态 Running

4.4 阻塞状态 Blocked

4.4.1 等待阻塞。

4.4.2 同步阻塞

4.4.3 其他阻塞

5.终止线程4种方式

5.1 正常运行结束。

5.2 使用退出标志退出线程。

5.3 Interrput方法结束线程

5.4stop方法终止线程(线程不安全)



1.Java并发知识库

java.util.concurrent

2.Java线程实现/创建方式

2.1 继承Thread类。

Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。

什么是native方法

public class MyTread extends Thread{

    public void run(){
        sout("run");
    }
}
MyTread myt = new MyTread();
myt.start();

2.2 实现Runnable接口

 

public class MyThread extends OtherClass implements Runnable {
    public void run() {
        System.out.println("MyThread.run()");
    }
}
//启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread 实例:
    MyThread myThread = new MyThread();
    Thread thread = new Thread(myThread);
    thread.start();
    //事实上,当传入一个Runnable target 参数给Thread 后,Thread 的run()方法就会调用
    target.run()
public void run() {
    if (target != null) {
    target.run();
    }
}

3.4种线程池

Java里面线程池的顶级接口时Executor,但是严格意义上讲,Executor并不是一个线程池,只是一个执行线程的工具,真正的线程池接口是ExecutorService.

3.1 newCachedThreadPool

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用他们,对于执行很多短期异步任务的程序而言,这些线程池通常可以提高程序性能。

3.2 newFixedThreadPool

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。

3.3 newScheduledThreadPool

创建一个线程池,可安排在给定延迟后运行命令或者定期地执行。

3.4 newSingleThreadExcutor

返回一个线程池,这个线程池可以在线程死后,重新启动一个线程来替代原来的线程继续执行下去。 

 

4.线程生命周期

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU 独自
运行,所以CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换

4.1 新建状态 New

当程序使用关键字new创建了一个线程之后,线程就处于新建状态, 由JVM为其分配内存,并初始化其成员变量的值。

4.2 就绪状态 Runnable

当线程对象调用start方法之后,该线程就处于就绪状态,JVM会为其创建方法调用栈和程序计数器,等待调度运行。

4.3 运行状态 Running

如果处于就绪状态的线程获得了CPU,开始执行run方法的线程执行体,该线程处于运行状态。

4.4 阻塞状态 Blocked

阻塞状态是指线程因为某种原因放弃了CPU的使用权,即让出了cpu时间片,暂时停止运行,直到线程进入可运行状态,才有机会再次获得时间片,转到运行状态。

4.4.1 等待阻塞。

运行running 的线程执行wait()方法,JVM会把该线程放入等待队列。

4.4.2 同步阻塞

运行running 的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池lock pool中。

4.4.3 其他阻塞

运行running的线程执行Thread.sleep 或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态,当sleep()状态超时,join()等待线程终止或者超时、或者IO处理完毕时,线程重新转入可运行状态

 

 

5.终止线程4种方式

5.1 正常运行结束。

5.2 使用退出标志退出线程。

一般run()方法执行完,线程就会正常结束。然而有些线程需要长时间运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,如boolean,设置true或者false控制while循环是否退出。

public class ThreadSafe extends Thread {
    public volatile boolean exit = false;
        public void run() {
            while (!exit){
        //do something
        }
    }
}

定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false,在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值。

另:volatile

volatile关键字的作用

5.3 Interrput方法结束线程

1.线程处于阻塞状态,如使用了sleep,同步锁的wait,socket种的receiver,accept等方法时,会使线程处于阻塞状态,当调用线程的interrupt方法时,会抛出InterruptException异常,阻塞种的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态, 从而让我们有机会结束这个线程。通常很多人认为只要调用interrupt 方法线程就会结束,实际上是错的, 一定要先捕InterruptedException 异常之后通过break 来跳出循环,才能正常结束run 方法。

2.线程未处于阻塞状态:使用isInterrupted判断线程的中断标志来退出循环,当使用interrupt方法时,中断标志就会置true。和使用自定义的标志来控制循环。

 

5.4stop方法终止线程(线程不安全)

程序中可以直接使用thread.stop来强行终止线程,但是很危险,就像突然关机,不安全主要是thread.stop调用之后,创建子线程的线程会抛出ThreadDeatheror的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用
thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),
那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。因此,并不推荐使用stop 方法来终止线程。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值