线程的常用方法及六种状态

一、线程核心执行流程方法 -- run()

        run方法是Runnable接口中定义的。所有实现Runnable的接口的子类都需要覆写run方法。

        run方法是线程的核心执行流程方法,也就是说,run方法决定了线程启动后要干什么,当run方法执行完毕(JVM启动run方法),线程会进入销毁状态。

二、启动线程-- start()

        start方法是Thread类定义的。start方法是启动线程调用的方法,只有当线程对象调用start方法之后才会被系统调度,进入运行状态。

        当线程启动之后,若再次调用start()方法,就会抛出IllegalThreadStateException(非法线程状态异常),说明该线程已经启动过了。

三、中断线程

        (一)通过共享变量中断线程

public class ThreadInterruptByVariable {
    private static class MyThread implements Runnable{
        volatile boolean isQuit = false;
        @Override
        public void run() {
            while (!isQuit){
                System.out.println(Thread.currentThread().getName() + "  别烦我,正在转账呢~~");
                try {
                    // 每次转账休眠1s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"被中断了");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyThread mt = new MyThread();
        Thread thread = new Thread(mt,"小A线程");
        System.out.println("小A可以开始转账了~");
        thread.start();
        // 主线程休眠3秒
        Thread.sleep(3000);
        System.out.println("钱转完了,让小A停止!");
        mt.isQuit = true;
    }
}

        (二)使用Thread.interrupted()(静态方法)或Thread对象的(成员方法)isInterrupted()

public class ThreadInterruptByMethod {
    private static class MyThread implements Runnable{
        @Override
        public void run() {
// 1. 静态方法,判断当前线程是否被中断了
//            while (Thread.interrupted()){
//2.成员方法,判断当前线程是否被中断了
            while (Thread.currentThread().isInterrupted()){
                System.out.println(Thread.currentThread().getName() + "  别烦我,正在转账呢~~");
                try {
                    // 每次转账休眠1s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("转账中断");
                    // 当线程被中断时,会抛出中断异常
                    // 抛出中断异常之后,中断状态就会还原!--》因为线程调用了sleep方法
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()+"被中断了");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyThread mt = new MyThread();
        Thread thread = new Thread(mt,"小A线程");
        System.out.println("小A可以开始转账了~");
        thread.start();
        // 主线程休眠3秒
        Thread.sleep(3000);
        System.out.println("钱转完了,让小A停止!");
        // 中断子线程
        // 调用此方法就会将子线程的状态置为中断状态
        thread.interrupted();
    }
}

thread 收到通知的方式有两种:

1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通 知,清除中断标志(无论是使用Thread.interrupted() 还是使用Thread.currentThread().isInterrupted(),状态都会从TRUE 重新置为 FALSE

        当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择 忽略这个异常, 也可以跳出循环结束线程.

2.线程没有调用以上方法,处在正常运行状态时收到中断通知thread.interrupt()

Thread.interrupted()判断当前线程是否被中断,若中断状态为true 清除中断标志 TRUE -->FALSE

Thread.currentThread.isInterrupted(); 判断指定线程对象是否状态为中断状态,若状态为true,不会清除中断标志。TRUE-->TRUE

线程的常用方法及六种状态_第1张图片

线程的常用方法及六种状态_第2张图片

四、等待线程--join()

线程的常用方法及六种状态_第3张图片

join方法---Thread类中定义的成员方法。 

线程对象. join():在哪个线程(A)中调用别的线程对象的join方法(B线程对象.join()),意思就是A线程要等待B线程执行完毕后再继续执行本线程的后续代码。

Eg:若在主线程中调用thread1.join(),主线程就会进入阻塞状态,直到thread1执行结束,主线程才会继续向后执行

public class ThreadJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "还在学习JavaSE阶段...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"JavaSE线程");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "进入数据结构的学习部分");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"数据结构线程");
        System.out.println("先学习JavaSE");
        t1.start();
        // 主线程死等t1,直到t1执行结束主线程再恢复执行
        t1.join();
        // 此时走到这里,t1线程已经执行结束,再启动t2线程
        t2.start();
        // 在哪调用别的线程的join方法,阻塞的是调用join的线程
        // main -> 调用t2.join() 阻塞主线程,直到t2完全执行结束再恢复主线程的执行
        // 主线程只等t2 2000ms - 2s,若t2在2s之内还没结束,主线程就会恢复执行
        t2.join(2000);
        // t2线程也执行结束了,继续执行主线程
        System.out.println("开始学习JavaEE");
        System.out.println(Thread.currentThread().getName());
    }
}

线程的常用方法及六种状态_第4张图片

五、休眠线程--sleep()

sleep():Thread类的静态方法,在哪个线程中调用,就休眠哪个线程

调用sleep方法的线程会让出CPU资源,从运行状态转为就绪状态,等待CPU继续调度。

线程的常用方法及六种状态_第5张图片

六、 yeild()

线程调用yeild()  ==》会从运行状态转为就绪状态!

调用yeild 方法的线程也会主动让出CPU资源,从运行状态转为就绪状态,等待CPU继续调度。

到底什么时候让出CPU ,什么时候又重新被CPU再次调度,都是操作系统OS调度的,我们无权选择

可能会出现以下情况:

  1. 让出后立马又被调度了
  2. 让出之后,很久都不调度

七、wait() 和 notify()

    线程间的等待与唤醒机制。wait()和 notify()是Object类的方法,用于线程的等待与唤醒,必须搭配synchronized锁来使用。

(一)等待方法

死等,线程进入waiting状态,直到有其他线程调用notify()将其唤醒

 等待一段时间,进入timed_waiting状态。若在该时间段内线程被唤醒,则继续执行,若超过相应时间还没有其它线程唤醒此线程,此线程也不再等待,恢复执行。

(二)唤醒方法

随机唤醒一个正处于等待状态的线程 

唤醒所有处于等待状态的线程 

(三)代码示例

        调用wait方法的前提是首先要获取到该对象的锁(synchronized对象锁),调用wait方法会释放锁,该线程进入等待队列等待被唤醒,被唤醒后不是立即恢复执行,而是进入阻塞状态,竞争锁。

public class WaitAndNotify {
    private static class WaitTask implements Runnable {
        private Object lock;
        public WaitTask(Object lock) {
            this.lock = lock;
        }
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + "准备进入等待状态");
                // 此线程在等待lock对象的notify方法唤醒
                try {
//调用 wait()的线程会进入waiting状态,等待被其他线程唤醒(lock.notify())
                    lock.wait();
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
//被唤醒结束后,线程从wait()之后开始继续执行
                System.out.println(Thread.currentThread().getName() + "等待结束,本线程继续执行");
            }
        }
    }
    private static class NotifyTask implements Runnable {
        private Object lock;
        public NotifyTask(Object lock) {
            this.lock = lock;
        }
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println("准备唤醒");
                // 随机唤醒一个处在lock对象上等待的线程
//                lock.notify();
                  lock.notifyAll();
                System.out.println("唤醒结束");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        // 创建三个等待线程
        Thread t1 = new Thread(new WaitTask(lock),"t1");
        Thread t2 = new Thread(new WaitTask(lock),"t2");
        Thread t3 = new Thread(new WaitTask(lock),"t3");
        // 创建一个唤醒线程
        Thread notify = new Thread(new NotifyTask(lock),"notify线程");
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(100);
        notify.start();
    }
}

线程的常用方法及六种状态_第6张图片

线程的常用方法及六种状态_第7张图片

 线程的常用方法及六种状态_第8张图片

()非法监视器状态异常

如果调用wait()和notify()没有获取锁[没有搭配synchronized锁来使用],就会排除非法的监视器状态异常

线程的常用方法及六种状态_第9张图片

八、线程的六种状态 

public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state:Thread.State.values()) {
            System.out.println(state);
        }
    }
}

线程的常用方法及六种状态_第10张图片

线程的常用方法及六种状态_第11张图片

  1. new :新建线程对象就是new状态
  2. Runnable : 新建状态的下一个状态,可执行状态(真正在运行的(Running)和即将开始执行的(Ready),都是这个状态)
  3. Blocked:锁等待,需要等待其他线程对象释放锁对象
  4. WAITTING:等待被另一个线程唤醒(notify方法)
  5. TIMED_WAITTING: 超时等待,需要等待一段时间后自动唤醒

 3,4,5 都是等待状态,都属于线程的阻塞状态(该线程需要暂缓执行,这三个造成暂缓执行的原因不同),当前线程暂停执行,等待其他任务或者资源

      6.Terminated: 终止状态,表示当前线程已经执行结束了,可以被销毁

线程的run方法执行完毕后,或者抛出异常不正常执行完毕都会进入终止状态。

你可能感兴趣的:(jvm,java)