Java多线程编程实战:10个经典练习题详解与代码实现

1. 创建两个线程分别打印“Hello”和“World”

背景

在多线程编程中,线程是程序执行的基本单位之一。通过创建多个线程,可以让程序同时执行多个任务。

实现思路

  • 使用Thread类创建两个线程。
  • 每个线程分别打印“Hello”和“World”。

代码实现

public class ThreadExample1 {
    public static void main(String[] args) {
        Thread helloThread = new Thread(() -> {
            System.out.println("Hello");
        });

        Thread worldThread = new Thread(() -> {
            System.out.println("World");
        });

        helloThread.start();
        worldThread.start();
    }
}

输出示例

Hello
World

2. 使用Thread类实现线程的启动和停止

背景

Thread类是Java中用于创建线程的类。线程的启动通过调用start()方法实现,而线程的停止可以通过设置一个标志变量来实现。

实现思路

  • 使用Thread类创建一个线程。
  • 在线程中通过一个标志变量控制线程的运行状态。
  • 在主线程中通过设置标志变量来停止线程。

代码实现

public class ThreadExample2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            boolean running = true;
            while (running) {
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    running = false;
                }
            }
            System.out.println("Thread stopped.");
        });

        thread.start();
        Thread.sleep(5000); // 主线程等待5秒后停止线程
        thread.interrupt(); // 通过中断线程来停止线程
    }
}

输出示例

Thread is running...
Thread is running...
Thread is running...
Thread stopped.

3. 使用Runnable接口实现线程

背景

Runnable接口是Java中用于实现多线程的接口。通过实现Runnable接口,可以将线程的逻辑封装到一个对象中,然后通过Thread类来运行。

实现思路

  • 定义一个类实现Runnable接口。
  • run()方法中实现线程的逻辑。
  • 使用Thread类来运行实现Runnable接口的对象。

代码实现

public class ThreadExample3 {
    public static void main(String[] args) {
        Runnable helloTask = () -> {
            System.out.println("Hello from Runnable");
        };

        Runnable worldTask = () -> {
            System.out.println("World from Runnable");
        };

        Thread helloThread = new Thread(helloTask);
        Thread worldThread = new Thread(worldTask);

        helloThread.start();
        worldThread.start();
    }
}

输出示例

Hello from Runnable
World from Runnable

4. 实现线程的同步,避免数据竞争

背景

在多线程环境中,多个线程可能会同时访问和修改共享资源,导致数据竞争和不一致的问题。通过线程同步机制可以避免这些问题。

实现思路

  • 使用synchronized关键字同步方法或代码块。
  • 确保多个线程访问共享资源时,只有一个线程可以执行同步代码。

代码实现

public class ThreadExample4 {
    private static int count = 0;

    public static void main(String[] args) {
        Runnable incrementTask = () -> {
            for (int i = 0; i < 1000; i++) {
                synchronized (ThreadExample4.class) {
                    count++;
                }
            }
        };

        Thread thread1 = new Thread(incrementTask);
        Thread thread2 = new Thread(incrementTask);

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + count);
    }
}

输出示例

Final count: 2000

5. 使用join方法等待线程结束

背景

join方法用于等待一个线程结束。主线程调用某个线程的join方法后,主线程会等待该线程执行完成后再继续执行。

实现思路

  • 创建一个线程并启动。
  • 在主线程中调用该线程的join方法,等待其结束。
  • 主线程继续执行。

代码实现

public class ThreadExample5 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("Thread is running...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread finished.");
        });

        thread.start();
        thread.join(); // 主线程等待thread线程结束

        System.out.println("Main thread continues...");
    }
}

输出示例

Thread is running...
Thread finished.
Main thread continues...

6. 使用sleep方法暂停线程

背景

sleep方法用于暂停当前线程的执行,指定的时间内线程不会运行。

实现思路

  • 在线程中调用Thread.sleep()方法,暂停线程的执行。
  • 指定暂停的时间(以毫秒为单位)。

代码实现

public class ThreadExample6 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("Thread started...");
            try {
                Thread.sleep(2000); // 暂停2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread resumed...");
        });

        thread.start();
    }
}

输出示例

Thread started...
(2秒后)
Thread resumed...

7. 使用volatile关键字确保线程间变量的可见性

背景

volatile关键字用于确保线程间变量的可见性。当一个变量被volatile修饰时,线程对变量的修改会立即写入主内存,其他线程可以立即看到变量的最新值。

实现思路

  • 使用volatile修饰一个变量。
  • 在一个线程中修改该变量的值。
  • 在另一个线程中读取该变量的值。

代码实现

public class ThreadExample7 {
    private static volatile boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (running) {
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread stopped.");
        });

        thread.start();
        Thread.sleep(5000); // 主线程等待5秒后停止线程
        running = false; // 修改volatile变量的值
    }
}

输出示例

Thread is running...
Thread is running...
Thread is running...
Thread stopped.

8. 使用synchronized块实现线程同步

背景

synchronized块用于同步代码块,确保多个线程访问共享资源时的线程安全。

实现思路

  • 使用synchronized块同步对共享资源的访问。
  • 指定同步块的锁对象。

代码实现

public class ThreadExample8 {
    private static int count = 0;
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Runnable incrementTask = () -> {
            for (int i = 0; i < 1000; i++) {
                synchronized (lock) {
                    count++;
                }
            }
        };

        Thread thread1 = new Thread(incrementTask);
        Thread thread2 = new Thread(incrementTask);

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + count);
    }
}

输出示例

Final count: 2000

9. 使用ExecutorService管理线程池

背景

ExecutorService是Java中用于管理线程池的接口。通过线程池可以复用线程,提高线程的利用率。

实现思路

  • 使用Executors工具类创建一个线程池。
  • 提交任务到线程池中执行。
  • 关闭线程池。

代码实现

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadExample9 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.submit(() -> {
            System.out.println("Task 1 executed by " + Thread.currentThread().getName());
        });

        executorService.submit(() -> {
            System.out.println("Task 2 executed by " + Thread.currentThread().getName());
        });

        executorService.shutdown(); // 关闭线程池
    }
}

输出示例

Task 1 executed by pool-1-thread-1
Task 2 executed by pool-1-thread-2

10. 使用CallableFuture实现线程的返回值

背景

Callable接口用于定义有返回值的任务,Future接口用于获取任务的返回值。

实现思路

  • 定义一个实现Callable接口的任务。
  • 提交任务到线程池中执行。
  • 使用Future获取任务的返回值。

代码实现

import java.util.concurrent.*;

public class ThreadExample10 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Callable<Integer> task = () -> {
            System.out.println("Task is running...");
            Thread.sleep(2000);
            return 42; // 返回值
        };

        Future<Integer> future = executorService.submit(task);

        System.out.println("Waiting for task to complete...");
        Integer result = future.get(); // 获取任务的返回值

        System.out.println("Task completed with result: " + result);

        executorService.shutdown();
    }
}

输出示例

Waiting for task to complete...
Task is running...
(2秒后)
Task completed with result: 42
posted @ 2025-04-06 09:40  软件职业规划  阅读(305)  评论(0)    收藏  举报