Android第十二次面试-多线程和字符串算法总结

发布于:2025-06-04 ⋅ 阅读:(22) ⋅ 点赞:(0)

多线程的创建与常见使用方法

一、多线程创建方式
1. 继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行逻辑
        System.out.println(Thread.currentThread().getName() + " is running");
    }
}

// 使用
MyThread thread = new MyThread();
thread.start(); // 启动线程
2. 实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running");
    }
}

// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();
​3. Android特有方式
// HandlerThread(自带Looper)
HandlerThread handlerThread = new HandlerThread("WorkerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 后台线程处理消息
    }
};

// 发送消息
handler.sendEmptyMessage(0);

二、线程池使用(推荐方式)​
1. 创建线程池
// 固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(4);

// 缓存线程池(自动扩容)
ExecutorService cachedPool = Executors.newCachedThreadPool();

// 单线程池(顺序执行)
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
2. 提交任务
// 执行Runnable任务
fixedPool.execute(() -> {
    System.out.println("Task running in thread pool");
});

// 提交Callable任务并获取Future
Future<String> future = fixedPool.submit(() -> {
    return "Task result";
});
3. 自定义线程池
ThreadPoolExecutor customPool = new ThreadPoolExecutor(
    4, // 核心线程数
    10, // 最大线程数
    60, // 空闲线程存活时间(秒)
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100) // 任务队列
);

// 拒绝策略(当队列满时)
customPool.setRejectedExecutionHandler((task, executor) -> {
    System.err.println("Task rejected: " + task);
});

1. 交替打印数字(两个线程协作)

题目​:两个线程交替打印1~100,一个线程打印奇数,另一个打印偶数

public class AlternatePrint {
    private int num = 1;
    private final Object lock = new Object();

    public void printOdd() {
        synchronized (lock) {
            while (num <= 100) {
                if (num % 2 == 1) {
                    System.out.println(Thread.currentThread().getName() + ": " + num++);
                    lock.notify(); // 唤醒偶数线程
                } else {
                    try {
                        lock.wait(); // 等待偶数线程通知
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    public void printEven() {
        synchronized (lock) {
            while (num <= 100) {
                if (num % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + ": " + num++);
                    lock.notify(); // 唤醒奇数线程
                } else {
                    try {
                        lock.wait(); // 等待奇数线程通知
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        AlternatePrint printer = new AlternatePrint();
        
        new Thread(printer::printOdd, "OddThread").start();
        new Thread(printer::printEven, "EvenThread").start();
    }
}
2. 生产者-消费者模型(缓冲区管理)

题目​:实现生产者线程生成数据,消费者线程消费数据,使用阻塞队列控制

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumer {
    private static final int CAPACITY = 5;
    private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(CAPACITY);

    public void produce() throws InterruptedException {
        int value = 0;
        while (true) {
            synchronized (this) {
                while (queue.size() == CAPACITY) {
                    wait(); // 缓冲区满时等待
                }
                
                queue.put(value);
                System.out.println("Produced: " + value);
                value++;
                notifyAll(); // 通知消费者
            }
            Thread.sleep(100); // 模拟生产耗时
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            synchronized (this) {
                while (queue.isEmpty()) {
                    wait(); // 缓冲区空时等待
                }
                
                int value = queue.take();
                System.out.println("Consumed: " + value);
                notifyAll(); // 通知生产者
            }
            Thread.sleep(150); // 模拟消费耗时
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        
        new Thread(() -> {
            try { pc.produce(); } 
            catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        }, "Producer").start();
        
        new Thread(() -> {
            try { pc.consume(); } 
            catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        }, "Consumer").start();
    }
}
3. 多线程顺序打印(线程协同)

题目​:三个线程按顺序循环打印ABC各10次

public class SequentialPrinter {
    private final Object lock = new Object();
    private String state = "A";

    public void printA() {
        synchronized (lock) {
            for (int i = 0; i < 10; ) {
                if (state.equals("A")) {
                    System.out.print("A");
                    state = "B";
                    i++;
                    lock.notifyAll(); // 唤醒所有等待线程
                } else {
                    try {
                        lock.wait(); // 等待条件满足
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    // 类似实现printB()和printC()
    public void printB() {
        synchronized (lock) {
            for (int i = 0; i < 10; ) {
                if (state.equals("B")) {
                    System.out.print("B");
                    state = "C";
                    i++;
                    lock.notifyAll();
                } else {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    public void printC() {
        synchronized (lock) {
            for (int i = 0; i < 10; ) {
                if (state.equals("C")) {
                    System.out.print("C ");
                    state = "A";
                    i++;
                    lock.notifyAll();
                } else {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        SequentialPrinter printer = new SequentialPrinter();
        
        new Thread(printer::printA, "Thread-A").start();
        new Thread(printer::printB, "Thread-B").start();
        new Thread(printer::printC, "Thread-C").start();
    }
}
4. 多线程计算素数(任务分发)

题目​:使用线程池计算1~N范围内素数的数量

import java.util.concurrent.*;

public class PrimeCounter {
    public static void main(String[] args) throws Exception {
        final int N = 1000000;
        final int THREADS = Runtime.getRuntime().availableProcessors();
        ExecutorService executor = Executors.newFixedThreadPool(THREADS);
        
        int segment = N / THREADS;
        Future<Integer>[] results = new Future[THREADS];
        
        // 分发任务
        for (int i = 0; i < THREADS; i++) {
            final int start = i * segment + 1;
            final int end = (i == THREADS - 1) ? N : (i + 1) * segment;
            
            results[i] = executor.submit(() -> {
                int count = 0;
                for (int num = start; num <= end; num++) {
                    if (isPrime(num)) count++;
                }
                return count;
            });
        }
        
        // 汇总结果
        int totalPrimes = 0;
        for (Future<Integer> future : results) {
            totalPrimes += future.get();
        }
        
        System.out.println("Total primes: " + totalPrimes);
        executor.shutdown();
    }
    
    private static boolean isPrime(int n) {
        if (n <= 1) return false;
        if (n == 2) return true;
        if (n % 2 == 0) return false;
        
        for (int i = 3; i <= Math.sqrt(n); i += 2) {
            if (n % i == 0) return false;
        }
        return true;
    }
}
5. 自定义简单线程池

题目​:实现一个固定大小的线程池,支持提交任务和执行任务

import java.util.concurrent.*;
import java.util.*;

public class SimpleThreadPool {
    private final BlockingQueue<Runnable> taskQueue;
    private final List<WorkerThread> workers;
    private volatile boolean isShutdown = false;

    public SimpleThreadPool(int poolSize) {
        this.taskQueue = new LinkedBlockingQueue<>();
        this.workers = new ArrayList<>();
        
        for (int i = 0; i < poolSize; i++) {
            WorkerThread worker = new WorkerThread("Worker-" + i);
            worker.start();
            workers.add(worker);
        }
    }
    
    public void execute(Runnable task) {
        if (isShutdown) {
            throw new IllegalStateException("ThreadPool is shutdown");
        }
        taskQueue.offer(task);
    }
    
    public void shutdown() {
        isShutdown = true;
        workers.forEach(Thread::interrupt);
    }
    
    private class WorkerThread extends Thread {
        public WorkerThread(String name) {
            super(name);
        }
        
        @Override
        public void run() {
            while (!isShutdown || !taskQueue.isEmpty()) {
                try {
                    Runnable task = taskQueue.take();
                    task.run();
                } catch (InterruptedException e) {
                    // 处理中断,结束线程
                }
            }
        }
    }
    
    public static void main(String[] args) {
        SimpleThreadPool pool = new SimpleThreadPool(4);
        
        // 提交任务
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() 
                    + " executing Task-" + taskId);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        
        // 等待任务完成
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        pool.shutdown();
    }
}

字符串算法总结

1. 字符串反转

题目​:反转字符串或单词顺序

// 整个字符串反转
public String reverseString(String s) {
    char[] chars = s.toCharArray();
    int left = 0, right = chars.length - 1;
    while (left < right) {
        char temp = chars[left];
        chars[left++] = chars[right];
        chars[right--] = temp;
    }
    return new String(chars);
}

// 单词顺序反转(保留空格)
public String reverseWords(String s) {
    String[] words = s.trim().split("\\s+");
    StringBuilder sb = new StringBuilder();
    for (int i = words.length - 1; i >= 0; i--) {
        sb.append(words[i]);
        if (i > 0) sb.append(" ");
    }
    return sb.toString();
}
2. 字符串转换整数 (atoi)

题目​:处理边界条件(空格/正负号/溢出)

public int myAtoi(String s) {
    int index = 0, sign = 1, total = 0;
    // 1. 跳过空格
    while (index < s.length() && s.charAt(index) == ' ') index++;
    if (index == s.length()) return 0;
    
    // 2. 处理正负号
    if (s.charAt(index) == '+' || s.charAt(index) == '-') {
        sign = s.charAt(index) == '+' ? 1 : -1;
        index++;
    }
    
    // 3. 转换数字并处理溢出
    while (index < s.length()) {
        int digit = s.charAt(index) - '0';
        if (digit < 0 || digit > 9) break;
        
        // 检查溢出
        if (total > Integer.MAX_VALUE / 10 || 
            (total == Integer.MAX_VALUE / 10 && digit > 7)) {
            return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
        }
        total = total * 10 + digit;
        index++;
    }
    return total * sign;
}
3. 最长公共前缀

题目​:查找字符串数组的最长公共前缀

public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0) return "";
    for (int i = 0; i < strs[0].length(); i++) {
        char c = strs[0].charAt(i);
        for (int j = 1; j < strs.length; j++) {
            if (i == strs[j].length() || strs[j].charAt(i) != c) {
                return strs[0].substring(0, i);
            }
        }
    }
    return strs[0];
}
4. 无重复字符的最长子串

题目​:滑动窗口经典应用

public int lengthOfLongestSubstring(String s) {
    Map<Character, Integer> map = new HashMap<>();
    int maxLen = 0;
    for (int left = 0, right = 0; right < s.length(); right++) {
        char c = s.charAt(right);
        if (map.containsKey(c)) {
            left = Math.max(left, map.get(c) + 1); // 跳过重复字符
        }
        map.put(c, right);
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}
5. 最长回文子串

题目​:中心扩展法

public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); i++) {
        int len1 = expand(s, i, i);      // 奇数长度
        int len2 = expand(s, i, i + 1);  // 偶数长度
        int len = Math.max(len1, len2);
        if (len > end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start, end + 1);
}

private int expand(String s, int left, int right) {
    while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
        left--;
        right++;
    }
    return right - left - 1;
}
6. 字符串匹配算法(KMP)

题目​:实现 strStr()

public int strStr(String haystack, String needle) {
    if (needle.isEmpty()) return 0;
    int[] next = getNext(needle);
    int i = 0, j = 0;
    while (i < haystack.length()) {
        if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
            i++;
            j++;
        } else {
            j = next[j];
        }
        if (j == needle.length()) {
            return i - j;
        }
    }
    return -1;
}

private int[] getNext(String pattern) {
    int[] next = new int[pattern.length()];
    next[0] = -1;
    int i = 0, j = -1;
    while (i < pattern.length() - 1) {
        if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
    return next;
}
7. 有效的括号

题目​:栈的经典应用

public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (c == '(') stack.push(')');
        else if (c == '[') stack.push(']');
        else if (c == '{') stack.push('}');
        else if (stack.isEmpty() || stack.pop() != c) 
            return false;
    }
    return stack.isEmpty();
}
8. 字母异位词分组

题目​:HashMap的巧妙使用

public List<List<String>> groupAnagrams(String[] strs) {
    Map<String, List<String>> map = new HashMap<>();
    for (String s : strs) {
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        String key = new String(chars);
        map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
    }
    return new ArrayList<>(map.values());
}
9. 编辑距离(动态规划)

题目​:计算最小操作次数

public int minDistance(String word1, String word2) {
    int m = word1.length(), n = word2.length();
    int[][] dp = new int[m + 1][n + 1];
    
    for (int i = 0; i <= m; i++) dp[i][0] = i;
    for (int j = 0; j <= n; j++) dp[0][j] = j;
    
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], 
                               Math.min(dp[i][j - 1], dp[i - 1][j]));
            }
        }
    }
    return dp[m][n];
}
10. 字符串解码

题目​:嵌套括号处理

public String decodeString(String s) {
    Stack<Integer> numStack = new Stack<>();
    Stack<StringBuilder> strStack = new Stack<>();
    StringBuilder cur = new StringBuilder();
    int num = 0;
    
    for (char c : s.toCharArray()) {
        if (Character.isDigit(c)) {
            num = num * 10 + (c - '0');
        } else if (c == '[') {
            numStack.push(num);
            strStack.push(cur);
            cur = new StringBuilder();
            num = 0;
        } else if (c == ']') {
            StringBuilder tmp = cur;
            cur = strStack.pop();
            int repeat = numStack.pop();
            for (int i = 0; i < repeat; i++) {
                cur.append(tmp);
            }
        } else {
            cur.append(c);
        }
    }
    return cur.toString();
}

网站公告

今日签到

点亮在社区的每一天
去签到