Java中的多线程是指在同一个Java虚拟机(JVM)中并发执行多个线程的能力。线程是程序执行的最小单元,Java提供了丰富的API来创建和管理线程。以下是Java中实现多线程的一些关键概念和方法:
-
Thread 类:Java提供了
Thread
类来创建和管理线程。通过继承Thread
类并重写其run()
方法,可以定义线程执行的任务。 -
Runnable 接口:Java还提供了
Runnable
接口,它包含一个run()
方法。实现Runnable
接口的类可以被传递给Thread
类的构造器,从而创建一个新的线程。 -
创建线程:可以通过继承
Thread
类或实现Runnable
接口来创建线程。然后,通过调用start()
方法启动线程。 -
生命周期:线程有几种状态,包括新建、就绪、运行、阻塞和死亡。线程状态的变化由线程的生命周期管理。
-
同步:当多个线程访问共享资源时,需要同步以避免数据不一致。Java提供了
synchronized
关键字和ReentrantLock
等同步机制。 -
线程池:Java提供了线程池(
ExecutorService
)来管理线程的创建和销毁,提高资源利用率和执行效率。 -
中断:线程可以被中断,这是线程间通信的一种方式。通过调用线程的
interrupt()
方法可以设置中断状态,而通过检查线程的isInterrupted()
方法可以响应中断。 -
等待/通知机制:Java提供了
wait()
、notify()
和notifyAll()
方法,允许线程在某些条件下等待,或在条件满足时被唤醒。 -
死锁:当多个线程相互等待对方释放资源时,可能会发生死锁。Java提供了工具和方法来检测和避免死锁。
-
并发集合:Java并发包(
java.util.concurrent
)提供了线程安全的集合类,如ConcurrentHashMap
、CopyOnWriteArrayList
等。
下面是一个简单的Java多线程示例,演示了如何创建和启动线程:
// 使用Runnable接口创建线程
class Task implements Runnable {
private int taskId;
public Task(int id) {
this.taskId = id;
}
@Override
public void run() {
System.out.println("Task " + taskId + " is running by " + Thread.currentThread().getName());
// 执行任务的代码
}
}
public class MultiThreadExample {
public static void main(String[] args) {
// 创建线程
Thread thread1 = new Thread(new Task(1), "Thread-1");
Thread thread2 = new Thread(new Task(2), "Thread-2");
// 启动线程
thread1.start();
thread2.start();
}
}
在这个示例中,我们定义了一个Task
类实现了Runnable
接口,并重写了run()
方法来执行任务。然后在main
方法中创建了两个线程,并通过调用它们的start()
方法来启动它们。
Java多线程编程是一个复杂的话题,涉及到线程安全、性能优化、资源管理等多个方面。正确地使用多线程可以提高程序的性能和响应能力,但同时也需要小心处理线程间的交互和同步问题。
在Java中,实现线程间的同步和互斥主要依赖于同步机制,以下是一些常用的方法:
-
synchronized 关键字:
- 可以用来修饰方法或者代码块。
- 当一个线程访问一个对象的
synchronized
方法或者同步代码块时,它会获得这个对象的锁。 - 其他线程必须等待锁释放后才能访问该对象的任何其他
synchronized
方法或同步代码块。
-
wait() 和 notify() 方法:
wait()
方法使当前线程等待,直到其他线程调用相同对象的notify()
或notifyAll()
方法。notify()
唤醒在此对象监视器上等待的单个线程,而notifyAll()
唤醒所有在此对象监视器上等待的线程。
-
Lock 接口和其实现类:
- Java并发API提供了
java.util.concurrent.locks.Lock
接口和一些实现类,如ReentrantLock
。 - 这些锁提供了与
synchronized
关键字类似的功能,但提供了更多的灵活性,例如尝试非阻塞获取锁、可中断的锁获取、超时等待等。
- Java并发API提供了
-
volatile 关键字:
- 确保变量的更新对所有线程立即可见。
- 当一个线程修改了一个
volatile
变量的值,新值会立即同步到主内存中,其他线程可以立即看到这个新值。
-
Atomic 类:
- Java并发API提供了一组原子类,如
AtomicInteger
、AtomicLong
等,它们利用CAS(Compare-And-Swap)操作来保证操作的原子性。
- Java并发API提供了一组原子类,如
-
Concurrent 集合:
java.util.concurrent
包提供了线程安全的集合类,如ConcurrentHashMap
、CopyOnWriteArrayList
等,它们内部实现了同步机制。
-
CountDownLatch、CyclicBarrier、Semaphore 和 Exchanger:
- 这些是Java并发API提供的同步辅助类,用于控制多个线程之间的协调。
下面是一个使用synchronized
关键字和wait()
/notify()
方法实现线程间同步的示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
System.out.println("Count: " + count);
// 当计数达到某个值时,通知等待的线程
if (count >= 5) {
notifyAll();
}
}
public synchronized void waitForCount() throws InterruptedException {
while (count < 5) {
wait();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
Thread incrementer = new Thread(() -> {
for (int i = 0; i < 10; i++) {
counter.increment();
}
});
Thread waiter = new Thread(() -> {
try {
counter.waitForCount();
System.out.println("Count has reached 5 or more.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
incrementer.start();
waiter.start();
}
}
在这个示例中,Counter
类有两个同步方法:increment()
和waitForCount()
。increment()
方法每次被调用时都会增加计数并打印当前计数。如果计数达到5或以上,它会调用notifyAll()
来唤醒等待的线程。waitForCount()
方法使用wait()
来等待计数达到5。
请注意,使用同步机制时,需要小心避免死锁和性能问题。正确的同步策略取决于具体的应用场景和需求。
笔者小,中,大厂均有面试经验,目前正在从事全栈开发工作,坚持每日分享java全栈开发知识与相关的面试真题,希望能够给大家带来帮助,同大家共同进步。