java线程的入口函数_Java线程基础

本文详细介绍了Java线程的五种状态:新建、就绪、运行、阻塞和死亡,以及线程的实现方式,包括继承Thread类、实现Runnable接口和使用Callable/FutureTask。此外,还探讨了线程操作如sleep、yield、wait、join和interrupt的方法区别,并分析了守护线程的概念及其与用户线程的区别。
摘要由CSDN通过智能技术生成

线程具有五中基本状态

新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

实现方式:

1.继承Thread类,重写run方法

2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target

3.通过Callable和FutureTask创建线程

1.继承Thread类,重写run方法

public class MyThread extendsThread {

@Overridepublic voidrun() {

System.out.println("MyThread:run");

}public static voidmain(String[] args) {

Thread thread= newMyThread();

thread.start();

}

}

2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target

public class MyRunnable implementsRunnable {

@Overridepublic voidrun() {

System.out.println("MyRunnable:run");

}public static voidmain(String[] args) {

Thread thread= new Thread(newMyRunnable());

thread.start();

}

}

3.通过Callable和FutureTask创建线程

public class MyCallable implements Callable{

@OverridepublicString call() {try{

System.out.println("MyCallable:run");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}return "MyCallable:call";

}public static voidmain(String[] args) {

MyCallable myCallable= newMyCallable();

FutureTask task = new FutureTask(myCallable);

Thread thread= newThread(task);

thread.start();try{

System.out.println(task.get());

}catch(InterruptedException e) {

e.printStackTrace();

}catch(ExecutionException e) {

e.printStackTrace();

}

}

}

task.get()的时候阻塞,直到会调用task的线程执行完返回后才继续

通过线程池提交的时候会返回Future

Future接口,只有五个方法比较简单

7391eed037f6c57f80555c7a35adda9e.png

线程的操作

sleep,yield,wait,join函数的区别

sleep:线程暂停执行,但不会释放“锁标志”,使用CPU可以调度其它线程。

yield:只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

wait:在synchronized包括的块中使用wait,线程暂停执行,会释放synchronized的“锁标志”。直到其它线程获取锁后调用notify()或notifyAll()后才会唤醒,但是并不会马上执行,需要调用notify()或notifyAll()的线程执行完释放锁后才会执行。

notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。

notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,

推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行。

join:等待调用的线程执行完后,在继续执行当前线程。

使用sleep和yield例子:

public class MyRunnable implementsRunnable {

@Overridepublic voidrun() {

Thread.yield();try{

Thread.sleep(3000); //暂停毫秒为单位,可以通过interrupt抛出异常

System.out.println(Thread.currentThread());

}catch(InterruptedException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {new Thread(newMyRunnable()).start();

}

}

wait使用:

public class MyRunnable implementsRunnable {privateObject value;publicMyRunnable(Object value) {this.value =value;

}

@Overridepublic voidrun() {synchronized(value) {try{

System.out.println("执行wait");

value.wait();

System.out.println(Thread.currentThread());

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}public static voidmain(String[] args) {

Object lock= newObject();new Thread(newMyRunnable(lock)).start();try{

Thread.sleep(2000);synchronized(lock) {

System.out.println("执行notify");

lock.notify();

}

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

执行结果:

d1f3db1369854854333ea0b9acc73037.png

可以发现是当线程调用wait后,是主线程调用了notify后,线程才继续执行

join例子:

public class MyRunnable implementsRunnable {

@Overridepublic voidrun() {try{

System.out.println("执行sleep");

Thread.sleep(5000);

System.out.println(Thread.currentThread());

}catch(InterruptedException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

Thread thread= new Thread(newMyRunnable());

thread.start();try{

thread.join();

System.out.println("执行join后");

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

执行结果

b1bec0d4dd81d130cd545a65082a3c79.png

interrupt操作

这个方法只会给线程设置一个为true的中断标志(中断标志只是一个布尔类型的变量),而设置之后,则根据线程当前的状态进行不同的后续操作。

1. 如果线程的当前状态处于非阻塞状态,那么仅仅是线程的中断标志被修改为true而已;

2. 如果线程的当前状态处于阻塞状态,那么在将中断标志设置为true后,还会有如下三种情况之一的操作:

(1) 如果是wait、sleep以及jion三个方法引起的阻塞,那么会将线程的中断标志重新设置为false,并抛出一个InterruptedException;

(2) 如果是java.nio.channels.InterruptibleChannel进行的io操作引起的阻塞,则会对线程抛出一个ClosedByInterruptedException;(待验证)

(3) 如果是轮询(java.nio.channels.Selectors)引起的线程阻塞,则立即返回,不会抛出异常。(待验证)

如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞状态的情况来进行处理;例如,一个线程在运行状态中,其中断标志被设置为true,则此后,一旦线程调用了wait、jion、sleep方法中的一种,立马抛出一个InterruptedException,且中断标志被清除,重新设置为false。

通过上面的分析,我们可以总结,调用线程类的interrupted方法,其本质只是设置该线程的中断标志,将中断标志设置为true,并根据线程状态决定是否抛出异常。因此,通过interrupted方法真正实现线程的中断原理是:开发人员根据中断标志的具体值,来决定如何退出线程。

public class MyRunnable implementsRunnable {

@Overridepublic voidrun() {try{

System.out.println("执行sleep");

Thread.sleep(5000); //当在暂停中调用interrupt,就抛出了异常InterruptedException

System.out.println(Thread.currentThread());

}catch(InterruptedException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

Thread thread= new Thread(newMyRunnable());

thread.start();

thread.interrupt();

}

}

执行结果:

69be08a5809ada23888f76b52c44ce38.png

setDaemon操作

线程默认false是用户线程,通过setDaemon(true)设置线程为守护线程

只能在start之前设置,不然会报IllegalThreadStateException异常

用户线程和守护线程的区别:

1.主线程结束后用户线程还会继续运行

2.如果没有用户线程,都是守护线程,那么JVM结束。

例子:

public class MyRunnable implementsRunnable {

@Overridepublic voidrun() {try{

System.out.println("执行sleep");

Thread.sleep(5000); //当在暂停中调用interrupt,就抛出了异常InterruptedException

System.out.println(Thread.currentThread());

}catch(InterruptedException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

Thread thread= new Thread(newMyRunnable());

thread.setDaemon(true);

thread.start();try{

Thread.sleep(2000);

System.out.println("结束程序");

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

结果:

9c2ca638dd479d5e78a1aa27655e2a23.png

可以看到没有等线程thread执行完,程序就结束了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值