面试题:多线程中的API以及sleep()和wait()的区别

多线程中的API

启动线程-start()

作用

start方法的作用就是启动一个线程,内部调用了run方法

示例

public class DaemonThread {
    public static void main(String[] args) {
         Thread t = new Thread(new Runnable() {
             @Override
             public void run() {
                 System.out.println(Thread.currentThread().getName());
             }
         });
         t.start();
        System.out.println(Thread.currentThread().getName());
    }
}

中断线程-interrupt()

方法说明

方法 说明
public void interrupt() 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置
public static boolean interrupted() 判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isinterrupted() 判断对象关联的线程的标志位是否设置,调用后不清除标志位

作用

  1. 通过thread对象调用interrupt()方法通知该线程停止运行
public static void test1() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){

                }
            }
        });
        t.start();
        t.interrupt();
    }
  1. thread收到通知的方式有两种:
    (1)如果线程调用了wait/join/sleep方法而阻塞挂起的,则以interruptedException异常的形式通知,清除中断标志;
public static void test2() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().isInterrupted());//true
                    Thread.sleep(3000);
                    //线程调用wait()/join()/sleep()阻塞时,如果把当前线程中断掉,会直接抛出一个异常
                    //阻塞状态时,通过捕获及处理异常,来处理线程的中断逻辑
                    //抛出异常后,线程标志位会进行重置
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().isInterrupted());//false
                }
            }
        });
        t.start();
        t.interrupt();
    }
(2)否则,只是内部的一个中断标志被设置,thread可以通过
①Thread.interrupted()判断当前线程的中断标志被设置,清除中断标志
 public static void test3(){
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                //线程运行状态时,需要自行判断线程的中断标志位
                while(!Thread.interrupted()){
                    System.out.println(Thread.currentThread().getName());
                }
            }
        });
        t.start();//t线程中的中断标志位=false
        t.interrupt();//t线程的中断标志位=true
    }
②Thread.currentThread().isInterrupted()判断指定线程的中断标志被设置,不清除中断标志
public static void test4() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
//                    System.out.println(Thread.interrupted());//返回中断标志位,并重置标志位
                    System.out.println(Thread.currentThread().isInterrupted());
                }
            }
        });
        t.start();//t线程中的中断标志位=false
        t.interrupt();//t线程的中断标志位=true
    }

等待线程-join()

方法说明

方法 说明
public void join() 等待线程结束
public void join(long mills) 等待线程结束,最多等mills毫秒
public void join(long mills,int nanos) 同理,但可以提高精度

作用

方法不带参数

public static void without() throws InterruptedException {
        //打印顺序:main -> thread-0
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        t.start();
        t.join();//等待t线程执行完毕
        System.out.println(Thread.currentThread().getName());
    }

方法带参数

public static void withoutSleep() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        t.start();
        //t线程执行时间和2秒钟谁先到,就以这个时间点作为main线程等待的时间点,到了这个时间点就往下执行
        //t执行完(比2秒钟快)就往下执行
        t.join(2000);
        System.out.println(Thread.currentThread().getName());
    }

wait()

作用

wait()方法就是使线程停止运行。

  1. 方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
  2. wait()方法只能在同步方法中或同步块中调用。如果调用wait()时,没有持有适当的锁,会抛出异常。
  3. wait()方法执行后,当前线程释放锁,线程与其它线程竞争重新获取锁

示例

public static void main(String[] args) throws InterruptedException {
Object object = new Object();
  synchronized (object) {
    System.out.println("等待中...");
    object.wait();
      System.out.println("等待已过...");
    } 
        System.out.println("main方法结束...");
}

notify()

作用

notify方法就是使停止的线程继续运行。
4. 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个
呈wait状态的线程。
5. 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

使用

1.wait,notify必须使用在synchronized同步方法或者代码块内
2.随机唤醒一个被wait阻塞的线程

notifyAll()

作用

与notify()相似,但是是唤醒被wait阻塞的全部线程

yield()

作用

yield()方法会暂停当前正在执行的线程对象,并执行其他线程,始终都是Runnable状态

示例

public class ThreadYield {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
        //等待new Thread线程执行完毕,否则一直等待
        while(Thread.activeCount() > 1){
            Thread.yield();//将当前线程由运行态->就绪态
        }
        System.out.println(Thread.currentThread().getName());
    }
}

sleep()和wait()的区别

  1. wait和sleep都会是线程进入阻塞状态,都是可中断方法,被中断后都会抛出异常;
  2. wait是Object的方法,sleep是Thread的静态方法;
  3. wait必须在Synchronized同步方法或代码块中,而sleep不需要;
  4. wait会释放锁,sleep不会释放锁;
  5. wait无超时设置的话会持续阻塞,必须等待唤醒,而sleep必然会有超时,一定会自己醒来;
  6. wait是Object的实例方法,需要在对象上调用,表示在其上等待;而sleep是静态方法,在当前线程上。

猜你喜欢

转载自blog.csdn.net/qq_43452252/article/details/105630801
今日推荐