一文读懂Java多线程原理:从线程的创建到锁的应用
- 实现Runnable接口实现Runnable接口需要定义一个run()方法,都需要调用start()方法来启动新线程。
Java是一门广泛使用的编程语言,它支持多线程编程,也就是说一个程序可以同时执行多个任务。而对于Java程序员来说,了解Java多线程原理是非常重要的。本文将从以下几个方面介绍Java多线程原理:
1. 线程的创建
在Java中,有两种方式可以创建新的线程:通过继承Thread类或者实现Runnable接口。下面我们分别来看一下这两种方式。
– 继承Thread类
继承Thread类并重写run()方法是最简单也最常见创建新线程的方式。下面是一个简单示例:
“`
public class MyThread extends Thread {
public void run() {
System.out.println(“Hello, World!”);
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
– 实现Runnable接口
实现Runnable接口需要定义一个run()方法,并且需要在构造函数中传入一个实现了该接口的对象作为参数。示例代码如下:
public class MyRunnable implements Runnable {
Thread thread = new Thread(new MyRunnable());
无论是继承Thread类还是实现Runnable接口,都需要调用start()方法来启动新线程。如果直接调用run()方法,则会在当前线程中执行。
2. 线程的状态
Java中的线程有几种状态:新建、就绪、运行、阻塞和死亡。下面我们来逐一介绍这些状态。
– 新建状态
当一个Thread对象被创建时,它处于新建状态。此时它还没有开始执行,也没有分配到CPU时间片。
– 就绪状态
当一个线程调用了start()方法后,它进入就绪状态。此时它已经准备好了并且等待分配CPU时间片以便开始执行。
– 运行状态
当一个线程获得了CPU时间片并开始执行时,它进入运行态。
– 阻塞状态
当一个正在运行的线程被另外一个对象所阻塞(如等待I/O操作完成或者等待获取锁)时,该线程进入阻塞态。
– 死亡状态
当run()方法执行完毕或者发生异常退出后,该线程进入死亡态。
3. 线程同步与锁
多个线程同时访问共享资源可能会导致数据不一致或者程序出错。为了解决这个问题,在Java中提供了synchronized关键字和Lock接口来实现线程同步。
– synchronized关键字
synchronized可以用于方法或者代码块中,保证同一时刻只有一个线程可以执行该方法或代码块。下面是一个简单的示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
public synchronized int getCount() {
return count;
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
for (int i = 0; i < 10000; i++) {
new Thread(() -> counter.increment()).start();
}
Thread.sleep(1000);
System.out.println(counter.getCount());
在上述示例中,Counter类的increment()和getCount()方法都加了synchronized关键字,保证了多个线程同时访问count变量时不会出错。
– Lock接口
Lock接口提供了比synchronized更为灵活的锁机制。它允许实现更复杂的同步结构,并且支持更细粒度的锁控制。下面是一个使用ReentrantLock实现锁机制的示例:
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
for (int i = 0; i < 10000; i++) {
new Thread(() -> counter.increment()).start();
}
Thread.sleep(1000);
System.out.println(counter.getCount());
}
在上述示例中,Counter类的increment()方法使用了ReentrantLock来控制并发访问count变量的问题。
4. 线程池
线程池是一种重用线程的技术。它通过预先创建一定数量的线程,并且将任务放到队列中等待执行,以此来提高程序性能和资源利用率。Java提供了Executor框架和ThreadPoolExecutor类来实现线程池技术。
下面是一个使用ThreadPoolExecutor实现线程池的示例:
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(2);
Future future1 = executor.submit(new Callable() {
@Override
public Integer call() throws Exception {
return 1 + 2;
}
});
Future future2 = executor.submit(new Callable() {
public Integer call() throws Exception {
return 3 + 4;
}
});
System.out.println(future1.get());
System.out.println(future2.get());
executor.shutdown();
在上述示例中,我们创建了一个大小为2的固定线程数的线程池,并提交了两个Callable任务。通过调用Future对象的get()方法可以获取任务执行的结果。
Java多线程编程是一项非常重要的技能,本文从线程的创建、状态、同步与锁以及线程池这几个方面介绍了Java多线程原理。掌握了这些知识后,我们就可以更好地进行Java多线程编程,提高程序性能和资源利用率。