程序员

java基础之多线程略解

2018-06-12  本文已影响4人  沈默的头号狗腿

java中的多线程是非常重要的一个知识点,下面我们就来简单的介绍下多线程的相关知识以及相关方法。

并发与并行

并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)

并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于间时间隔较短,使人感觉两个任务都在运行。

线程的五种状态

新建,就绪,运行,阻塞,死亡

JVM启动的是多线程

JVM启动至少启动了垃圾回收线程主线程,所以是多线程的。

java中线程的实现方式

1,继承Thread

使用步骤:

1.定义类继承Thread

2.重写run方法

3.把新线程要做的事写在run方法中

4.创建线程对象

5.开启新线程, 内部会自动执行run方法

2,实现Runnable接口

实现步骤:

1.定义类实现Runnable接口

2.实现run方法

3.把新线程要做的事写在run方法中

4.创建自定义的Runnable的子类对象,创建Thread对象传入Runnable

5.调用start()开启新线程, 内部会自动调用Runnable的run()方法

3,通过Callable<V>接口和 FutureTask<V>创建线程

实现步骤:

1.创建Callable接口的实现类,设置V的类型,并实现call()方法,该call()方法将作为线程执行体,并且有返回值,返回值类型为V类型。

2.创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

3.使用FutureTask对象作为Thread对象的target创建并启动新线程。(能作为target是因为FutureTask实现了Runnale接口)

4.调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

例:

以上三种创建方式的区别

继承Thread : 由于子类重写了Thread类的run(), 当调用start()时直接找子类的run()方法。

实现Runnable : 构造函数中传入了Runnable的引用, 有个成员变量记住了它, 调用run()方法时内部判断成员变量Runnable的引用是否为空。

通过Callable接口和FutureTask创建线程:FutureTask是Runnbale的实现类,所以与Runnable相同,并且也是调用run方法,只是FutureTask将run方法重写了,在run方法中调用call方法。

继承Thread

好处是:可以直接使用Thread类中的方法,代码简单。

弊端是:如果已经有了父类,就不能用这种方法。

实现Runnable接口

好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,代码更灵活。

弊端是:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂。

通过Callable接口和FutureTask创建线程

好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,代码更灵活。并且call方法有返回值,还能抛出异常。

弊端是:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂相对于实现Runnable接口的方式更加复杂。

获取线程名字和设置名字

通过Thread的getName()方法获取线程对象的名字。

通过setName(String)方法可以设置线程对象的名字。

通过构造函数可以传入String类型的名字。

每个线程系统都会默认分配个名字,主线程:main,子线程thread-0 ....

获取当前线程的对象

Thread.currentThread()方法用于获取当前线程对象。

线程的其它方法

Thread.sleep(毫秒), 控制当前线程休眠若干毫秒。

setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出。特点:男守护女,女的死,男的也不想活了。

join(), 当前线程暂停, 等待指定的线程执行结束后,当前线程再继续,记住哪个线程调用该方法,则先执行哪个线程。

join(int), 可以等待指定的毫秒之后继续。

join方法详解:join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法(这里是将B线程对象设为A线程在等待池中的标识),当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法(通过标识可以在等待池中找到A线程然后唤醒)唤醒A线程,从而达到同步的目的。

yield() 线程让出cpu。

setPriority()设置线程的优先级,默认优先级是5,最小优先级1,最高优先级10,可以设置2,3,4,Thread里面有静态常量。

interrupt(),中断线程。

interrupt方法详解:Thread.interrupt 的作用不是中断线程,而是通知线程应该中断了,

如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。此时我们可以在catch中关闭线程。

如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true。被设置中断标志的线程将继续正常运行,不受影响。这种情况下,如果我们需要关闭线程,我们可以通过Thread.currentThread.isInterrupted()来判断中断标志是否为true,如果是,那么我们可以进行关闭线程处理,如下图所示,当中断标志为true时,循环结束,run方法执行完毕。

new Thread(new Runnable() {

public void run() {

while(!Thread.currentThread().isInterrupted()) {

System.out.println("线程的中断标志变为false时,执行我");

}

System.out.println("线程的中断标志变为true时,执行我");

}

}).start();

要记住的是,isInterrupted()返回中断标志后,会将中断标志设为false。

关闭线程的几种方式

1.设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止,如果是循环,那么我们可以设置当不符合循环条件时跳出循环,或者在循环代码中用if判断条件,不符合则通过break退出循环。

2.使用interrupt()方法中断线程,至于如何关闭上面已经说明。

3.使用stop方法强行终止线程(不推荐使用,Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!)。

上一篇 下一篇

猜你喜欢

热点阅读