21xrx.com
2024-11-10 00:54:28 Sunday
登录
文章检索 我的文章 写文章
解密经典线程面试题并使用Java代码实现
2023-06-17 01:12:39 深夜i     --     --
线程 synchronized 原子类 线程池

线程面试题一直是面试者和面试官关注的焦点。经典的线程面试题主要涉及线程的创建与销毁、线程同步与互斥、以及Java线程相关知识点。本文将对几个经典的线程面试题进行解析,并附带Java代码实现。

1. 谈谈线程的状态以及如何从一个状态转变为另一个状态?

线程的状态是指线程在某一时刻处于的状态,Java线程的状态一般包括如下几种:

- NEW(新建状态):新创建的线程处于此状态

- RUNNABLE(可执行状态):线程被创建后,其他线程或操作系统准备好它的资源,线程进入该状态

- BLOCKED(阻塞状态):线程由于等待锁对象或其他条件,阻塞当前线程的执行

- WAITING(等待状态):线程被要求等待新的条件,一直保持到其他线程显式地通知它继续执行

- TIMED_WAITING(定时等待状态):与WAITING状态相似,不同的是进行等待的时间可以是有限的

- TERMINATED(终止状态):线程已经执行完毕或者发生了异常而结束

线程的状态转化可以由线程自身操作(如wait()、notify()等),也可以由系统调度器进行调整。

下面是一个Java代码示例,演示了线程状态间的转化过程,代码中使用了Thread类的sleep方法来模拟程序执行过程中发生的线程状态转化:


public class ThreadStateTest {

  public static void main(String[] args) throws InterruptedException {

    Object object = new Object();

    Thread t1 = new Thread(() -> {

      synchronized (object) {

        try {

          Thread.sleep(1000L);

          object.wait(); 

        } catch (InterruptedException e) {

          e.printStackTrace();

        }

      }

    });

    t1.start();

    Thread.sleep(200L);

    // 输出:Thread[main,5,main]:WAITING(on object monitor)

    System.out.println(Thread.currentThread() + ":" + Thread.currentThread().getState());

    Thread.sleep(200L);

    // 输出:Thread[Thread-0,5,main]:BLOCKED(on object monitor)

    System.out.println(t1 + ":" + t1.getState());

    synchronized (object) {

      object.notifyAll();

    }

    Thread.sleep(200L);

    // 输出:Thread[Thread-0,5,main]:TERMINATED

    System.out.println(t1 + ":" + t1.getState());

  }

}

2. 如何实现线程安全?

在多线程程序中,由于多个线程共享同一个资源,可能会出现线程安全问题,即线程之间的数据不一致性以及对数据的损坏等情况。为了解决线程安全问题,我们一般采用以下方式:

- 使用同步方法:在方法前添加synchronized关键字,确保方法中的代码在同一时刻只有一个线程执行。

- 使用同步代码块:使用synchronized关键字配合锁对象(一般为共享资源)对共享资源进行同步处理。

- 使用原子类:Java提供了一些原子类,这些类的方法保证了操作的原子性,即线程安全。

下面是一个Java代码示例,演示了synchronized关键字以及原子类的使用:


import java.util.concurrent.atomic.AtomicInteger;

public class ThreadSafeTest {

  // 锁对象

  private static final Object lock = new Object();

  // 共享变量

  private static int count = 0;

  // 原子类

  private static AtomicInteger atomicCount = new AtomicInteger(0);

  public static void main(String[] args) {

    // 使用同步方法

    Thread t1 = new Thread(ThreadSafeTest::increase);

    Thread t2 = new Thread(ThreadSafeTest::increase);

    t1.start();

    t2.start();

    try {

      t1.join();

      t2.join();

    } catch (InterruptedException e) {

      e.printStackTrace();

    }

    // 此处输出 20000

    System.out.println("使用同步方法处理:count = " + count);

    // 使用原子类

    Thread t3 = new Thread(ThreadSafeTest::increaseAtomic);

    Thread t4 = new Thread(ThreadSafeTest::increaseAtomic);

    t3.start();

    t4.start();

    try {

      t3.join();

      t4.join();

    } catch (InterruptedException e) {

      e.printStackTrace();

    }

    // 此处输出 20000

    System.out.println("使用原子类处理:count = " + atomicCount.get());

  }

  private static void increase() {

    for (int i = 0; i < 10000; i++) {

      synchronized (lock) {

        count++;

      }

    }

  }

  private static void increaseAtomic() {

    for (int i = 0; i < 10000; i++) {

      atomicCount.incrementAndGet();

    }

  }

}

3. Java中的线程池以及适用场景

线程池作为一种线程的重用模式,在Java中应用广泛。使用线程池可以减少线程的创建、销毁等操作,从而提高程序效率。在实际开发过程中,线程池适用于以下场景:

- 服务器端使用:服务器一般需要同时处理大量的请求,使用线程池来维护一定的线程数可以更高效地处理请求。

- 批量处理任务:许多需要处理的任务可以以任务队列的形式提交到线程池中进行处理,使用线程池可以更方便的控制任务的并发数量。

- GUI应用开发:图形用户界面应用中一般需要响应用户交互事件,使用线程池可以保证用户能够更好地与应用程序进行交互。

以下是一个Java代码示例,演示了线程池的使用以及可能发生的线程安全问题:


import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPoolTest {

  // 共享变量

  private static int count = 0;

  // 原子类

  private static AtomicInteger atomicCount = new AtomicInteger(0);

  public static void main(String[] args) {

    ExecutorService executorService = Executors.newFixedThreadPool(10);

    for (int i = 0; i < 10000; i++) {

      executorService.submit(ThreadPoolTest::increase);

    }

    executorService.shutdown();

    while (!executorService.isTerminated()) {

      try {

        Thread.sleep(100L);

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

    }

    // 此处输出 100000

    System.out.println("使用线程池处理:count = " + count);

    ExecutorService executorService1 = Executors.newFixedThreadPool(10);

    for (int i = 0; i < 10000; i++) {

      executorService1.submit(ThreadPoolTest::increaseAtomic);

    }

    executorService1.shutdown();

    while (!executorService1.isTerminated()) {

      try {

        Thread.sleep(100L);

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

    }

    // 此处输出 100000

    System.out.println("使用线程池及原子类处理:count = " + atomicCount.get());

  }

  private static void increase() {

    count++;

  }

  private static void increaseAtomic() {

    atomicCount.incrementAndGet();

  }

}

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复