一文读懂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);

一文读懂Java多线程原理:从线程的创建到锁的应用

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多线程编程,提高程序性能和资源利用率。