Thread

2023-12-28 11:03:54


一个线程就是一个执行流程. 每个线程都可以按照顺序执行自己的代码, 而多个线程可以同时执行多份代码

1.生命周期

在这里插入图片描述
Thread有六个生命周期

  1. 新建(NEW)
    当一个Thread对象被创建时,它处于新建状态。在这个阶段,线程还没有启动。
public static void main(String[] args) throws Exception{
    System.out.println("Thread State is:"+new Thread().getState());
}
  1. 就绪(Runnable)
    当调用线程对象的start()方法后,线程进入就绪状态。在就绪状态下,线程已经准备好运行,但还没有得到 CPU 时间片。
public static void main(String[] args) {
   new Thread(() -> {
        System.out.println("Thread State is:"+Thread.currentThread().getState());
    }).start();
}
  1. 运行(Running)
    线程获得CPU时间片后,进入运行状态。在运行状态下,线程执行具体的任务代码。
  2. 阻塞(Blocked)
    线程在某些情况下会由于某些原因放弃CPU时间片,进入阻塞状态。例如,线程等待某个资源的释放,或者调用了sleep()方法。
public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();//锁
        BlockThread t1 = new BlockThread(lock,"T1");
        BlockThread t2 = new BlockThread(lock,"T2");
        t1.start(); //线程 T1开始运行
        t2.start(); //线程 T2开始运行
        Thread.sleep(100);  //阻塞主线程,等待T1,T2抢锁
        System.out.println("Thread T1 State is " + t1.getState());  //获取T1线程状态
        System.out.println("Thread T2 State is " + t2.getState());  //获取T2线程状态
    }
}

class BlockThread extends Thread {
    private String name;    //当前线程名称
    private Object lock;    //锁

    public BlockThread(Object lock, String name) {
        this.lock = lock;
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("Thread " + name + " State is " + Thread.currentThread().getState());
        synchronized (lock) {
            System.out.println("Thread " + name + " hold the lock");
            try {
                System.out.println("Thread " + name + " State is " + Thread.currentThread().getState());
                Thread.sleep(1000 * 10);    //抢到锁的线程执行逻辑,这里用睡眠模拟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread " + name + " release the lock");
        }
    }
}
  1. 等待(Waiting)
    线程在等待某个条件的触发时进入等待状态。例如,调用Object.wait()方法或者 Thread.join()方法。
public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        WaitingThread t = new WaitingThread("T", lock);
        t.start();
        Thread.sleep(1000);
        System.out.println("Thread T State is " + t.getState());
        System.out.println("Thread "+Thread.currentThread().getName()+" State is " + Thread.currentThread().getState());
    }
}

class WaitingThread extends Thread {
    private Object lock;
    public WaitingThread(String name, Object lock) {
        super(name);
        this.lock = lock;
    }

    @Override
    public void run() {
        System.out.println("Thread " + Thread.currentThread().getName()+" try to wait");
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 超时等待(Timed Waiting): 类似于等待状态,但有一个超时时间。例如,调用 Thread.sleep() 方法或者带有超时参数的 Object.wait() 方法。
  2. 终止(Terminated)
    线程执行完毕或者因异常退出时,进入终止状态。线程一旦终止,就不能再进入其他状态。

阻塞和等待的区别

阻塞状态等待状态
原因当线程试图获得一个对象的锁, 但该锁已经被其他线程持有时, 线程会进入阻塞状态当线程在某个对象上调用Object.wait()方法时, 它会进入等待状态, 等待期间会释放对象的锁
解除当持有锁的线程释放锁时, 被阻塞的线程有机会重新竞争锁, 并进入就绪状态线程可以通过调用Object.notify()或Object.notifyAll()来被唤醒,也可以在等待期间等待超时
是否会释放持有的锁在阻塞状态下, 线程仍然保持对锁的所有权在等待状态下, 线程会释放锁, 让其他线程有机会获得锁

阻塞状态结束后, 线程重新进入就绪状态,
在等待状态中, 线程可以被唤醒, 被唤醒的线程将重新进入就绪状态, 并尝试获取对象的锁

2.构造方法

Thread() :创建一个默认设置的线程对象实例
Thread(Runnable target) :创建一个包含可执行对象的线程实例
Thread(Runnable target, String name) :创建一个包含可执行对象,指定名称的线程对象
Thread(String name):创建一个指定名称的线程对象
Thread(ThreadGroup group, Runnable target) :创建一个指定线程组,包含可执行对象的线程对象实例
Thread(ThreadGroup group, Runnable target, String name) :创建一个指定线程组,包含可执行对象,指定线程名称的线程对象实例
Thread(ThreadGroup group, Runnable target, String name, long stackSize) :创建一个指定线程组、包含可执行对象、指定名称以及堆栈大小的线程对象实例
Thread(ThreadGroup group, String name):创建一个指定线程组,线程名称的线程实例

3.创建线程的方式

1.继承Thread类

public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        // 继承Thread
        MyThread thread1 = new MyThread();
        thread1.start();

        // 匿名内部类
        Thread thread2 =new Thread() {
            @Override
            public void run() {
                System.out.println("Hello World 2");
            }
        };
        thread2.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Hello World");
    }
}

2.实现Runnable接口

public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        // 继承Thread
        Thread thread1 = new Thread(new MyRunnable());
        thread1.start();

        // 匿名内部类
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World 2");
            }
        });
        thread2.start();
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello World");
    }
}

3.实现Callable接口
FutureTask 是一个类,它实现了 Runnable 和 Future 接口

Callable不能直接交给Thread来运行, 我们可以使用FutureTask包装Callable, 让它变成一个Runnable

public class FutureTaskThreadDemo {
    public static void main(String[] args) {
        // 创建一个实现 Callable 接口的匿名类实例,该实例在 call() 方法中返回一个字符串
        Callable<String> callableTask = new Callable<String>() {
            @Override
            public String call() throws Exception {
                // 在这里执行你的任务,并返回结果
                String result = "Hello from Callable!";
                return result;
            }
        };
 
        // 使用 Callable 任务创建一个 FutureTask 实例
        FutureTask<String> futureTask = new FutureTask<>(callableTask);
 
        // 创建一个新线程,并将 FutureTask 作为参数传递给它
        Thread taskThread = new Thread(futureTask);
 
        // 启动新线程,这将执行 FutureTask 中的 Callable 任务
        taskThread.start();
 
        try {
            // 从 FutureTask 对象中获取计算结果,如果任务尚未完成,此方法会阻塞等待
            String result = futureTask.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException e) {
            // 当前线程在等待过程中被中断时抛出 InterruptedException
            e.printStackTrace();
        } catch (ExecutionException e) {
            // 计算任务抛出异常时抛出 ExecutionException
            e.printStackTrace();
        }
    }
}

4.常用的方法

添加链接描述
1.join
join()方法, 作用是让一个线程等待另一个线程执行结束

如果线程A中调用了线程B的join()方法, 那么线程A将会等待线程B执行完成, 然后再继续执行

join方法有以下几个特点:

  1. 等待: 调用join的线程将阻塞, 直到被调用的线程执行完成
  2. 顺序执行: 如果在主线程中调用多个线程的join方法, 那么这些线程将按照调用join的顺序依次执行
public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new MyRunnable(), "Thread-1");
        Thread thread2 = new Thread(new MyRunnable(), "Thread-2");

        // 启动线程1
        thread1.start();
        thread1.join();

        // 启动线程2
        thread2.start();

    }

}

class MyRunnable implements Runnable {
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(100); // 模拟一些耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

文章来源:https://blog.csdn.net/qq_24099547/article/details/135246214
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。