1、多线程的状态
- 线程在一定条件下,状态会发生变化。线程一共有以下几种状态
- 新建状态(New): 创建一个新的线程对象
- 就绪状态(Runnable): 线程对象创建后,调用该对象的start()方法,改线程就进入到就绪状态。这意味着线程已经准备好执行,等待系统分配处理器资源。
- 运行(Running) :线程获得了处理器资源,开始执行run()方法中的代码。这是线程处于活动状态的阶段。
- 阻塞(Blocked):线程在等待某个条件满足时进入阻塞状态。例如,线程可能在等待I/O操作完成或者等待获取锁。
- 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
public class MyThread{public static void main(String[] args) throws Exception {Thread thread=new Thread(() -> {System.out.println("线程进入可运行状态");try {Thread.sleep(1000); } 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());}
}
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、 线程中常用的方法
- start():开始执行线程的方法,java虚拟机会调用线程内的run()方法;
- yield():yield在英语里有放弃的意思,同样,这里的yield()指的是当前线程愿意让出对当前处理器的占用。这里需要注意的是,就算当前线程调用了yield()方法,程序在调度的时候,也还有可能继续运行这个线程的;
- sleep():静态方法,使当前线程睡眠一段时间;
- join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的wait方法实现的;
- wait():当一个线程调用一个对象的 wait() 方法时,它会释放该对象的锁,然后进入等待状态。直到其他线程调用相同对象的 notify() 或 notifyAll() 方法来唤醒它。被唤醒后,线程会尝试重新获取对象的锁,并在成功获取锁之后继续执行。如果在调用 wait() 之前没有持有对象的锁,那么会抛出 IllegalMonitorStateException。
- notify(): 当一个线程调用一个对象的 notify() 方法时,它会随机唤醒在该对象上等待的一个线程(如果有的话)。被唤醒的线程将从等待池中移除,并尝试重新获取对象的锁。如果多个线程在等待,只有一个线程会被唤醒。如果没有线程在等待,那么调用 notify() 没有任何效果。
- notifyAll():与 notify() 类似,但不同之处在于它会唤醒所有在该对象上等待的线程。这些线程都将从等待池中移除,并尝试重新获取对象的锁。如果没有线程在等待,那么调用 notifyAll() 同样没有任何效果。
4.wait(), notify(), 和 notifyAll() 必须在同步块或同步方法中使用,因为它们依赖于对象的内置锁。此外,为了避免死锁和活锁等问题,通常使用更高级的并发工具,如 java.util.concurrent 包中的 Lock 和 Condition。
3、线程中添加返回值
- 使用Callable接口和FutureTask类。Callable接口允许你定义一个任务,该任务在执行完成后可以返回一个结果。FutureTask类是一个实现了Runnable接口的类,它接受一个Callable对象作为参数,并在调用run()方法时执行该任务
示例代码:
public class MyThread implements Callable<Integer> {@Overridepublic Integer call() throws Exception {Thread.sleep(1000);return 2;}public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService= Executors.newSingleThreadExecutor();MyThread myThread=new MyThread();Future<Integer> submit = executorService.submit(myThread);System.out.println(submit.get());ExecutorService executor = Executors.newCachedThreadPool();FutureTask<Integer> futureTask = new FutureTask<>(new MyThread());executor.submit(futureTask);System.out.println(futureTask.get());}
}
3、线程间通信
- Java多线程的等待/通知机制是基于Object类的wait()方法和notify(), notifyAll()方法来实现的
public class MyThread{private static volatile int signal = 0;static class ThreadA implements Runnable {@Overridepublic void run() {while (signal < 5) {if (signal % 2 == 0) {System.out.println("threadA: " + signal);synchronized (this) {signal++;}}}}}static class ThreadB implements Runnable {@Overridepublic 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();}
}
public class MyThread{private static volatile boolean flag = false;public static void main(String[] args) {Thread thread1 = new Thread(() -> {while (!flag) {}System.out.println("当前flag:"+flag);});Thread thread2 = new Thread(() -> {try {Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}flag = true; });thread1.start();thread2.start();}
}
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结束");}
}