线程相关总结

1、Object类的wait()、notify();Thread类中接口、synchronized关键字。

五种状态:

New 新建状态:线程被创建后就进入到了新建状态,Thread thread=new Thread();

Runnable 就绪状态:线程被创建后,其他线程调用该线程的start方法来启动该线程。处于就绪状态的线程,随时可能被CPU调度。

Running 运行状态:线程获取CPU执行。线程只能从就绪状态转为运行状态。

Blocked 阻塞状态: 线程因为某种原因放弃CPU的使用。只有直到线程进入到就绪状态,才有机会转入运行状态。

等待阻塞: 调用线程的wait()方法,让线程等待某工作完成。

同步阻塞: 线程在获取synchronized同步锁失败(同步锁被其他线程占用),会进入到同步阻塞状态。

其他阻塞: 通过调用线程的sleep()或join或发出IO请求。

Dead 死亡状态:线程执行完毕或者因为一场退出run()方法。

2、实现多线程的两种方式

  • 实现runnable接口

  • 继承Thread类,该类实现了runnable接口

Thread 和 Runnable 的相同点:都是“多线程的实现方式”。

Thread 和 Runnable 的不同点:

Thread 是类,而Runnable是接口;Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。

此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。

通常,建议通过“Runnable”实现多线程!

3、start()和run()的区别

start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
run() : run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!

target是一个runnale对象,run()就是直接调用Thread的Runnable的run()方法。

4、Synchronized关键字

在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。

当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。

不同线程对同步锁的访问是互斥的。

原则

第一条:当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

第二条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。

第三条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

5、线程的等待与唤醒

在Object类中定义了wait()、notify()和notifyAll()等接口;

wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁;
而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程;

Object类中关于等待/唤醒的API详细信息如下:

notify() – 唤醒在此对象监视器上等待的单个线程。

notifyAll() – 唤醒在此对象监视器上等待的所有线程。

wait() – 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。

wait(long timeout) – 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

wait(long timeout, int nanos) – 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

6、线程让步

方法:yieId()
作用:让步,让当前的线程由运行状态进入到就绪状态,从而让其他具有相同优先级的线程获得执行权。但是不能保证其他线程就一定能获得执行权,也有可能是当前线程又进入到运行状态继续运行。

yieId和wait区别:

(01) wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而不yield()是让线程由“运行状态”进入到“就绪状态”。

(02) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。

7、线程休眠

sleep在一下Thread类中,作用是让当前的线程休眠,即当前线程会从运行状态进入到阻塞状态。当时间到了的时候,会从阻塞状态变为就绪状态,等待CPU调度。

sleep和wait的比较:

wait的作用是让当前线程由运行状态进入到阻塞状态,同时释放掉同步锁。而sleep的作用也是让当前线程进入到阻塞状态,但是不会释放掉同步锁。

8、join

join()定义在Thread类中。
作用为:让“主线程”等待“子线程”结束之后才运行。

9、interrupt()和线程终止方式

interrupt()的作用是中断本线程。本线程中断自己是被允许的,其他线程调用本线程的interrupt方法的时候,会通过checkAccess()检查权限,这有可能抛出SecurityException异常。

通常我们会通过中断方式终止处于“阻塞状态”的线程。

当线程由于调用了sleep()、wait()、join()等方法而进入到阻塞状态;此时若调用线程的interrupt()方法将线程的中断标记设为了true,由于处于阻塞状态,中断标记会被清除,同时产生一个interruptException异常。将interruptException放在适当的位置就能终止线程;

interrupt()并不会终止“运行状态”的线程,它会将线程的中断标记设为true。(通过isInterrupted()方法判断线程是不是处于中断状态)。

终止线程的通用写法:

@Override
public void run() {
    try {
        // 1. isInterrupted()保证,只要中断标记为true就终止线程。
        while (!isInterrupted()) {
            // 执行任务...
        }
    } catch (InterruptedException ie) {  
        // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
    }
}

interrupted() 和 isInterrupted()都能够用于检测对象的“中断标记”。
区别是,interrupted()除了返回中断标记之外,它还会清除中断标记(即将中断标记设为false);而isInterrupted()仅仅返回中断标记。

10、线程优先级和守护线程

Java 中的线程的优先级是1—10,默认优先级是5。

Java中有两种线程,用户线程和守护线程。可以通过isDaemon()(守护线程)方法来区别。用户线程一般执行用户级线程,而守护线程也就是后台线程。

PS:Java虚拟机在“用户线程”都结束后退出。

猜你喜欢

转载自blog.csdn.net/qq_32454537/article/details/81159808