JAVA多线程

1、多线程的状态

  • 线程在一定条件下,状态会发生变化。线程一共有以下几种状态
  1. 新建状态(New): 创建一个新的线程对象
  2. 就绪状态(Runnable): 线程对象创建后,调用该对象的start()方法,改线程就进入到就绪状态。这意味着线程已经准备好执行,等待系统分配处理器资源。
  3. 运行(Running) :线程获得了处理器资源,开始执行run()方法中的代码。这是线程处于活动状态的阶段。
  4. 阻塞(Blocked):线程在等待某个条件满足时进入阻塞状态。例如,线程可能在等待I/O操作完成或者等待获取锁。
  5. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
  • 代码示例1
  • 多线程的几种状态 (无阻塞)
java 复制代码
public class MyThread{
    public static void main(String[] args) throws Exception {
      Thread thread=new Thread(() -> {
          System.out.println("线程进入可运行状态");
          try {
              Thread.sleep(1000); // 让线程休眠1秒,模拟执行任务
          } catch (InterruptedException e) {
              throw new RuntimeException(e);
          }
      });
        // 打印线程初始状态
        System.out.println("线程初始状态: " + thread.getState());
        // 启动线程
        thread.start();
        // 打印线程可运行状态
        System.out.println("线程可运行状态: " + thread.getState());
        // 主线程等待子线程执行完毕
        thread.join();
        // 打印线程终止状态
        System.out.println("线程终止状态: " + thread.getState());
    }
}
  • 代码示例2
  • 线程的几种状态(包含阻塞)
java 复制代码
public class MyThread {

    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private static boolean flag = false;

    public static void main(String[] args) throws Exception {
        Thread thread1 = new Thread(() -> {
            try {
                System.out.println("线程1进入可运行状态");
                lock.lock();
                while (!flag) {
                    condition.await(); // 等待条件满足
                }
                System.out.println("线程1继续执行");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                System.out.println("线程2进入可运行状态");
                Thread.sleep(3000);
                lock.lock();
                flag = true;
                condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        // 打印线程初始状态
        System.out.println("线程1初始状态: " + thread1.getState());
        System.out.println("线程2初始状态: " + thread2.getState());
        // 启动线程
        thread1.start();
        thread2.start();
        // 打印线程可运行状态
        System.out.println("线程1可运行状态: " + thread1.getState());
        System.out.println("线程2可运行状态: " + thread2.getState());
        try {
            // 主线程等待子线程执行完毕
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 打印线程终止状态
        System.out.println("线程1终止状态: " + thread1.getState());
        System.out.println("线程2终止状态: " + thread2.getState());
    }
}
输出结果:
线程1初始状态: NEW
线程2初始状态: NEW
线程1可运行状态: RUNNABLE
线程2可运行状态: RUNNABLE
线程1进入可运行状态
线程2进入可运行状态
线程1继续执行
线程1终止状态: TERMINATED
线程2终止状态: TERMINATED
--------------------------------------
public class MyThread {

    public static void main(String[] args) {
        Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程1等待");
                    lock.wait();
                    System.out.println("线程1继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("线程2唤醒线程1");
                lock.notify();
            }
        });

        thread1.start();
        thread2.start();
    }
}

输出结果:
线程1等待
线程2唤醒线程1
线程1继续执行

2、 线程中常用的方法

  • Thread类的几个常用的方法
  1. start():开始执行线程的方法,java虚拟机会调用线程内的run()方法;
  2. yield():yield在英语里有放弃的意思,同样,这里的yield()指的是当前线程愿意让出对当前处理器的占用。这里需要注意的是,就算当前线程调用了yield()方法,程序在调度的时候,也还有可能继续运行这个线程的;
  3. sleep():静态方法,使当前线程睡眠一段时间;
  4. join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的wait方法实现的;
  • Object类的几个常用的方法
  1. wait():当一个线程调用一个对象的 wait() 方法时,它会释放该对象的锁,然后进入等待状态。直到其他线程调用相同对象的 notify() 或 notifyAll() 方法来唤醒它。被唤醒后,线程会尝试重新获取对象的锁,并在成功获取锁之后继续执行。如果在调用 wait() 之前没有持有对象的锁,那么会抛出 IllegalMonitorStateException。
  2. notify(): 当一个线程调用一个对象的 notify() 方法时,它会随机唤醒在该对象上等待的一个线程(如果有的话)。被唤醒的线程将从等待池中移除,并尝试重新获取对象的锁。如果多个线程在等待,只有一个线程会被唤醒。如果没有线程在等待,那么调用 notify() 没有任何效果。
  3. notifyAll():与 notify() 类似,但不同之处在于它会唤醒所有在该对象上等待的线程。这些线程都将从等待池中移除,并尝试重新获取对象的锁。如果没有线程在等待,那么调用 notifyAll() 同样没有任何效果。
    4.wait(), notify(), 和 notifyAll() 必须在同步块或同步方法中使用,因为它们依赖于对象的内置锁。此外,为了避免死锁和活锁等问题,通常使用更高级的并发工具,如 java.util.concurrent 包中的 Lock 和 Condition。

3、线程中添加返回值

  • 使用Callable接口和FutureTask类。Callable接口允许你定义一个任务,该任务在执行完成后可以返回一个结果。FutureTask类是一个实现了Runnable接口的类,它接受一个Callable对象作为参数,并在调用run()方法时执行该任务
    示例代码:
java 复制代码
public class MyThread implements Callable<Integer> {


    @Override
    public Integer call() throws Exception {
        Thread.sleep(1000);
        return 2;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //方法1
        ExecutorService executorService= Executors.newSingleThreadExecutor();
        MyThread myThread=new MyThread();
        Future<Integer> submit = executorService.submit(myThread);
        // 注意调用get方法会阻塞当前线程,直到得到结果。
        // 所以实际编码中建议使用可以设置超时时间的重载get方法。
        System.out.println(submit.get());

        //方法2
        ExecutorService executor = Executors.newCachedThreadPool();
        FutureTask<Integer> futureTask = new FutureTask<>(new MyThread());
        executor.submit(futureTask);
        System.out.println(futureTask.get());
        //方法3
		ExecutorService executorService = Executors.newFixedThreadPool(5);
        Callable<String> task = () -> {
            // 在这里执行你的任务逻辑
            return "Hello from thread: " + Thread.currentThread().getName();
        };
        Future<String> submit = executorService.submit(task);
        String rs =  submit.get();
        System.out.println(rs);
    }
}

3、线程间通信

  • Java多线程的等待/通知机制是基于Object类的wait()方法和notify(), notifyAll()方法来实现的
java 复制代码
public class MyThread{

    private static volatile int signal = 0;
    static class ThreadA implements Runnable {
        @Override
        public void run() {
            while (signal < 5) {
                if (signal % 2 == 0) {
                    System.out.println("threadA: " + signal);
                    synchronized (this) {
                        signal++;
                    }
                }
            }
        }
    }
    static class ThreadB implements Runnable {
        @Override
        public void run() {
            while (signal < 5) {
                if (signal % 2 == 1) {
                    System.out.println("threadB: " + signal);
                    synchronized (this) {
                        signal = signal + 1;
                    }
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        new Thread(new ThreadA()).start();
        Thread.sleep(1000);
        new Thread(new ThreadB()).start();
    }
}
  • 使用volatile关键字
java 复制代码
public class MyThread{
    private static volatile boolean flag = false;

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            while (!flag) {
                // 等待flag变为true
            }
            System.out.println("当前flag:"+flag);
        });

        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟一些操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true; // 修改flag的值
        });

        thread1.start();
        thread2.start();
    }
}
  • 使用join
java 复制代码
public class MyThread{

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("我是子线程,我先睡一秒");
                Thread.sleep(1000);
                System.out.println("我是子线程,我睡完了一秒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
        thread.join();
        System.out.println("main结束");
    }
}
相关推荐
小灰灰要减肥15 分钟前
装饰者模式
java
张铁铁是个小胖子26 分钟前
MyBatis学习
java·学习·mybatis
Yan.love1 小时前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶1 小时前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥1 小时前
java提高正则处理效率
java·开发语言
智慧老师2 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm2 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
V+zmm101342 小时前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob3 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-13143 小时前
常用的缓存技术都有哪些
java