Skip to content

thread

线程状态

  • New
    • 创建后尚未启动
  • Runnable
    • os ready和runnable
    • 正在运行或者等待cpu时间片
  • blocking
    • 加(排他)锁,线程释放了锁则结束此状态
  • Time waiting 限期等待
    • 不需要其他线程显式的唤醒,在一定时间后被系统自动唤醒
    • Thread.sleep()
    • Thread.join(Long timeout) 时间结束,线程执行完毕
    • Object.wait(long timeout)
    • LockSupport.parkNanos parkutil
  • waiting 无限期的等待
    • 等待其他线程显式的唤醒,否则不会分配时间片
    • Object.wait()
    • Thread.join()
    • LockSupport.park()
  • terminated
    • 线程执行完毕之后,或者产生异常而结束

线程的实现

callable 可以有返回值(返回值通过futureTask封装) runnable 没有返回值

java
public class DemoCall {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }

    public static class MyCallable implements Callable {
        @Override
        public Object call() throws Exception {
            for (int i = 0; i < 5; i++) {
                System.out.println("my callable");
            }
            return 1;
        }
    }
}


package com.jasper;

/**
 * Hello world!
 *
 */
public class DemoRun
{
    public static void main( String[] args )
    {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);//new
        thread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("main Thread");
        }
    }

    public static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("my runnable");
//            try {
//                Thread.sleep(2000);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
            }
        }
    }
}

public class DemoThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
    public static class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("myThread");
            }
        }
    }

}

run 和start的区别

java
package com.jasper.thread.impl;

public class DemoThread {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
//        myThread.run();
        myThread.start();
        for (int i = 0; i < 5; i++) {
            Thread.sleep(100);
            System.out.println("mainThread");
        }
    }
    public static class MyThread extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (int i = 0; i < 5; i++) {
                System.out.println("myThread");
            }
        }
    }

}
//只是普通方法调用,不会启动新线程
//start 真正启动一个新线程,run() 方法会在新的线程中被执行。
//run 这里是顺序执行的
//start 是并发执行的

线程机制

守护线程

守护线程(Daemon Thread)是一种特殊的线程,它主要用于为其他线程(用户线程)提供服务, 比如垃圾回收线程就是一种典型的守护线程。当JVM中不存在任何活动的用户线程时,JVM将退出,不会等待守护线程完成。 因此,守护线程通常用于执行一些应用程序中不关键的任务

java
package com.jasper.First;

public class LogCleanerDaemon {
    public static void main(String[] args) {
        // 创建一个守护线程
        Thread logCleanerThread = new Thread(() -> {
            System.out.println("日志清理守护线程启动");

            while (true) {
                try {
                    // 模拟清理日志文件的操作
                    cleanLogs();
                    // 每隔10秒钟执行一次清理
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    // 处理中断异常
                    e.printStackTrace();
                }
            }
        });

        // 设置为守护线程
        logCleanerThread.setDaemon(true);
        // 启动守护线程
        logCleanerThread.start();

        // 模拟应用程序的其他操作
        try {
            System.out.println("应用程序正在运行");
            Thread.sleep(30000); // 模拟应用程序运行了一段时间后结束
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("应用程序结束");
        // 应用程序结束时,守护线程也会自动结束
    }

    private static void cleanLogs() {
        // 这里只是打印消息模拟清理日志文件的操作
        System.out.println("清理旧的日志文件...");
        // 实际应用中,这里应该添加清理日志文件的代码
    }
}

yield()

该方法声明线程已经完成了生命周期中最重要的部分,让出cpu时间片,可以切换给其他线程来执行,只是对调度器的一个建议

InterruptedException

InterruptedException是Java中的一个异常,它是Exception的一个子类, 用来指示线程在等待、睡眠,或者是占用的状态中被中断。在多线程编程中,这个异常主要用于指示一个线程希望另一个线程停止正在进行的操作。 当一个线程处于阻塞状态(例如,调用了Thread.sleep(long millis)方法进入睡眠,或者等待某个同步的资源 join), 其他线程可以通过调用这个线程的interrupt()方法来请求中断这个阻塞状态。被中断的线程在其阻塞调用中会抛出InterruptedException,从而提前结束这个阻塞状态

java
package com.jasper.interrupt;

public class Demo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("thread:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        thread.start();
        System.out.println("main Thread"+Thread.currentThread().getName());
        thread.interrupt();
    }
}

interrupted()

如果一个线程的run方法是一个无限循环,并且没有执行sleep等抛出InterruptedException的方法,

那么调用interrupt就不会使得线程中断,但是调用interrupt方法会设置线程的中断标志,此时调用interrupted()方法会返回true

java
package com.jasper.interrupt;

import static java.lang.Thread.interrupted;

public class Demo1 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!interrupted()) {
                System.out.println(Thread.currentThread().getState()+"--" + Thread.currentThread().getName());
            }
            System.out.println(Thread.currentThread().getName() + "end");
        });
        thread.start();
        for (int i = 0; i < 4; i++) {
            System.out.println("main");
        }
        System.out.println(Thread.currentThread().getName()+" end");
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        thread.interrupt();
    }
}
  • interrupted() 是一个静态方法,用于检查当前线程是否被中断。
  • 它会返回当前线程的中断状态(truefalse)。
  • 最重要的是,调用 interrupted() 方法会清除线程的中断状态。也就是说,如果线程被中断(中断状态为true),调用 interrupted() 之后,线程的中断状态会被重置为false
  • 这个方法实际上检查的是调用该方法的线程的中断状态,而不是创建 Thread 对象的线程的中断状态。
java
public class TestInterrupted {
    public static void main(String[] args) {
        // 中断当前线程(这里是main线程)
        Thread.currentThread().interrupt();
        
        // 检查并清除中断状态
        System.out.println("Is interrupted? " + Thread.interrupted()); // true
        // 再次检查中断状态
        System.out.println("Is interrupted again? " + Thread.interrupted()); // false
    }
}

isInterrupted()

  • isInterrupted() 是一个实例方法,用于检查调用该方法的线程对象是否被中断。
  • 它也会返回线程的中断状态(truefalse)。
  • interrupted() 不同,调用 isInterrupted() 方法 不会清除线程的中断状态。无论调用前后,线程的中断状态都保持不变。
java
public class TestIsInterrupted extends Thread {
    public void run() {
        // 模拟任务,这里只是简单的循环
        for(int i = 0; i < 100000; i++) {
            // 任务代码
        }
        // 检查中断状态
        System.out.println("Is interrupted? " + this.isInterrupted()); // true or false depending on whether it was interrupted
    }

    public static void main(String[] args) {
        TestIsInterrupted thread = new TestIsInterrupted();
        thread.start();
        // 中断线程
        thread.interrupt();
    }
}

总结

  • 使用 interrupted() 检查并清除当前线程的中断状态。
  • 使用 isInterrupted() 检查调用此方法的线程对象(某个线程 具体的thread实例)的中断状态,而不影响中断状态标志。
  • 选择哪个方法取决于你是否需要清除中断状态以及你是在检查当前线程还是其他线程的中断状态。

join()

在线程中调用另外一个线程的join方法,会将当前线程挂起,等到另外一个线程执行完,才会继续执行当前线程

java
package com.jasper.join;
public class JoinDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.print(i + "A ");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread thread1 = new Thread(() -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (int i = 0; i < 5; i++) {
                System.out.print(i + "B ");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread1.start();
        thread.start();
    }
}

wait notify

调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程

java
package com.jasper.waitnotify;
public class WaitNotifyDemo {
    public static void main(String[] args) {
        final  Object monitor = new Object();
        Thread before = new Thread(() -> {
            synchronized (monitor) {
                try {
                    monitor.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("before");
            }
        });
        Thread  after = new Thread(() -> {
            synchronized (monitor) {
                monitor.notify();
                System.out.println("after");
            }
        });
        before.start();
        after.start();
    }
}
  1. 属于 Object 类:wait() 是 java.lang.Object 类的一个方法,这意味着所有的 Java 对象都继承了这个方法。它用于让当前线程等待,直到另一个线程调用相同对象上的 notify() 或 notifyAll() 方法。
  2. 需要在同步块中使用:wait() 必须在同步方法或同步块中使用,因为它需要对象的监视器(monitor)。
  3. 释放锁:调用 wait() 会导致当前线程释放对象的锁,进入对象的等待池中,直到其他线程调用此对象上的 notify() 或 notifyAll() 方法。
  4. 主要用途:用于线程间的通信,特别是在生产者-消费者问题中。

await signal signalAll

是java.util.concuurent下面的

与await相比,可以增加条件

java
package com.jasper.waitnotify;

import com.jasper.lock.LockDemo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class AwaitDemo {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    public void before(){
        lock.lock();
        System.out.println("before");
        condition.signal();
        lock.unlock();
    }

    public void after(){
        lock.lock();
        try {
            condition.await();
            System.out.println("after");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        lock.unlock();
    }

}

wait() 和 sleep() 的区别

wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法; wait() 会释放锁,sleep() 不会