答案:Java中创建和启动线程需定义任务并调用start()方法。可通过实现Runnable接口或继承Thread类定义任务,前者更灵活且推荐;启动时调用start()而非run(),因start()由JVM创建新线程并执行run(),而直接调用run()仅在当前线程执行,无并发效果。

Java中创建和启动线程,核心思路其实很简单:你需要定义一个线程要执行的任务(也就是它要“跑”的代码),然后把这个任务交给一个线程对象,最后让这个线程对象“动起来”。具体来说,我们通常通过实现
Runnable
Thread
start()
在Java里创建并启动线程,最常见且推荐的做法有两种:实现
Runnable
Thread
1. 实现Runnable
这是更灵活也更推荐的方式。你定义一个类去实现
Runnable
run()
run()
立即学习“Java免费学习笔记(深入)”;
class MyRunnableTask implements Runnable {
private String taskName;
public MyRunnableTask(String name) {
this.taskName = name;
}
@Override
public void run() {
// 这就是线程要执行的任务代码
System.out.println(Thread.currentThread().getName() + " 正在执行任务: " + taskName);
try {
// 模拟任务执行耗时
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 的任务被中断了。");
Thread.currentThread().interrupt(); // 重新设置中断状态
}
System.out.println(Thread.currentThread().getName() + " 任务 " + taskName + " 完成。");
}
}
// 如何启动:
// MyRunnableTask task1 = new MyRunnableTask("任务A");
// Thread thread1 = new Thread(task1, "工作线程-A"); // 将任务封装进Thread对象
// thread1.start(); // 启动线程这种方式的好处在于,你的任务类可以继续继承其他类,因为Java是单继承的。同时,多个
Thread
Runnable
2. 继承Thread
另一种方式是直接创建一个类继承
Thread
run()
class MyThreadWorker extends Thread {
private String workerName;
public MyThreadWorker(String name) {
super(name); // 调用父类构造器设置线程名
this.workerName = name;
}
@Override
public void run() {
// 线程的业务逻辑
System.out.println(Thread.currentThread().getName() + " 启动,作为工作者: " + workerName);
try {
Thread.sleep(150);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 被中断了。");
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " 完成工作。");
}
}
// 如何启动:
// MyThreadWorker worker1 = new MyThreadWorker("专属工人-1");
// worker1.start(); // 直接启动Thread子类实例这种方式虽然也能工作,但由于Java的单继承限制,如果你的类还需要继承其他父类,就不能再继承
Thread
Runnable
3. 使用Lambda表达式(Java 8+)
对于简单的任务,我们还可以结合Lambda表达式来创建和启动线程,代码会更加简洁:
// new Thread(() -> {
// System.out.println(Thread.currentThread().getName() + " 正在执行一个匿名任务。");
// // ... 任务逻辑 ...
// }).start();无论哪种方式,关键都是调用
start()
这个问题其实挺基础,但很多初学者可能都会在这里犯迷糊。说实话,我刚开始学的时候也纳闷过,
run()
start()
答案是:start()
run()
当你调用
thread.start()
Runnable
Thread
run()
run()
但如果你直接调用
thread.run()
run()
举个例子,你有一个
MyRunnableTask
task
new Thread(task).start();
task.run()
task.run();
task
run()
所以,记住,
start()
run()
线程的生命周期,在我看来,就像是一个人的成长过程,从出生到消亡,中间会经历各种状态。理解这些状态对于调试和优化多线程程序至关重要。Java的
Thread.State
NEW (新建) 当一个
Thread
start()
Thread t = new Thread(() -> System.out.println("Hello")); // t 处于 NEW 状态RUNNABLE (可运行/运行中) 当线程调用了
start()
t.start(); // t 进入 RUNNABLE 状态
BLOCKED (阻塞) 当线程试图获取一个内部锁(
synchronized
synchronized
// 假设有两个线程同时尝试进入一个同步方法
public synchronized void syncMethod() {
// ...
}
// 如果一个线程在执行syncMethod,另一个线程调用syncMethod就会进入BLOCKED状态WAITING (等待) 线程进入WAITING状态通常是因为调用了以下方法之一:
Object.wait()
Thread.join()
LockSupport.park()
notify()
notifyAll()
join
// 线程A调用 obj.wait(); // 线程B调用 obj.notify(); 才能唤醒线程A
TIMED_WAITING (定时等待) 与WAITING类似,但它会等待一个指定的时间。如果时间到了,即使没有被其他线程唤醒,线程也会自动回到RUNNABLE状态。进入TIMED_WAITING状态的方法包括:
Thread.sleep(long millis)
Object.wait(long millis)
Thread.join(long millis)
LockSupport.parkNanos(long nanos)
LockSupport.parkUntil(long deadline)
Thread.sleep(1000); // 线程进入 TIMED_WAITING 状态
TERMINATED (终止) 当线程的
run()
// 当 t 的 run() 方法执行完毕后,t 就会进入 TERMINATED 状态
理解这些状态以及它们之间的转换条件,对于诊断多线程程序的性能问题(比如死锁、活锁、线程饥饿)非常关键。在实际开发中,我经常会用JStack或者IDE的调试工具来查看线程的当前状态,这能帮助我快速定位问题。
多线程编程就像是在一个厨房里,多个厨师(线程)同时操作食材(共享资源)。如果大家各干各的,不注意协作,就很容易出问题。线程安全问题是多线程编程中避不开的坎,我个人觉得,理解这些问题以及对应的解决方案,是写出健壮并发程序的基石。
常见的线程安全问题:
竞态条件 (Race Condition): 这是最常见的问题。当多个线程尝试访问和修改同一个共享资源(比如一个变量、一个集合)时,如果操作的最终结果依赖于这些线程执行的相对时序,就可能发生竞态条件。结果往往是不可预测的、错误的。 例子: 多个线程同时对一个计数器
i++
i++
死锁 (Deadlock): 两个或更多的线程被无限期地阻塞,互相等待对方释放资源。这就像两个哲学家,每人拿着一只筷子,都在等对方放下另一只筷子才能吃饭,结果谁也吃不了。 死锁发生的四个必要条件:
活锁 (Livelock): 线程虽然没有被阻塞,但它们却在不断地改变状态以响应其他线程,导致没有任何实际的进展。它比死锁更隐蔽,因为线程看起来是活跃的,但实际上是无效的忙碌。 例子: 两个人过窄桥,同时走到中间,都想给对方让路,于是同时向左,又同时向右,结果谁也过不去。
饥饿 (Starvation): 一个或多个线程由于调度策略不公平,或者优先级太低,或者总是得不到所需的资源,而导致它们永远无法获得CPU时间或资源来执行任务。
解决方案:
针对这些问题,Java提供了丰富的工具和机制:
synchronized
synchronized
// 同步方法
public synchronized void increment() {
count++;
}
// 同步代码块
public void update() {
synchronized (this) { // 或 synchronized (someObject)
// 访问共享资源的代码
}
}synchronized
java.util.concurrent.locks
ReentrantLock
ReadWriteLock
ReentrantLock
synchronized
tryLock()
lockInterruptibly()
// ReentrantLock lock = new ReentrantLock();
// lock.lock();
// try {
// // 访问共享资源
// } finally {
// lock.unlock();
// }ReadWriteLock
java.util.concurrent.atomic
AtomicInteger
AtomicLong
AtomicReference
// AtomicInteger counter = new AtomicInteger(0); // counter.incrementAndGet(); // 原子地执行 i++
volatile
volatile
volatile
synchronized
// public volatile boolean flag = false; // 当一个线程修改 flag 为 true 时,其他线程能立即看到这个变化。
并发集合 (Concurrent Collections):
java.util.concurrent
ConcurrentHashMap
CopyOnWriteArrayList
BlockingQueue
// ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
// map.put("key", "value"); // 线程安全不可变对象 (Immutable Objects): 如果一个对象在创建后其状态就不能再被修改,那么它就是线程安全的。例如
String
ThreadLocal
// private static ThreadLocal<Integer> threadCount = ThreadLocal.withInitial(() -> 0); // threadCount.get(); // 获取当前线程的副本 // threadCount.set(1); // 设置当前线程的副本
在实际开发中,选择哪种解决方案,往往需要根据具体场景、性能要求以及代码的复杂性来权衡。我通常会优先考虑使用并发集合和原子类,如果不行再考虑
ReentrantLock
synchronized
这确实是一个老生常谈的问题,但它背后的考量却很实际。我个人的经验是,在绝大多数情况下,实现Runnable
我们来深入分析一下:
1. 实现Runnable
Thread
Runnable
// class MyBusinessLogic extends SomeBaseClass implements Runnable { ... }
// 这种组合在继承Thread时是不可能实现的。Runnable
Thread
Runnable
Thread
// MyRunnableTask task = new MyRunnableTask(); // new Thread(task).start(); // 一个任务 // new Thread(task).start(); // 另一个线程执行同一个任务实例
Runnable
Runnable
Thread
Runnable
// Counter counter = new Counter(); // 共享的计数器实例 // new Thread(new MyRunnable(counter)).start(); // new Thread(new MyRunnable(counter)).start(); // 两个线程操作同一个 counter 对象
Runnable
2. 继承Thread
Thread
Runnable
Callable
Thread
Thread
什么时候可以考虑继承Thread
坦白说,我几乎很少直接继承
Thread
Thread
总结我的选择偏好:
在实际开发中,我几乎总是会选择实现
Runnable
ExecutorService
ExecutorService
Runnable
Callable
Runnable
以上就是Java中如何创建和启动线程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号