您的位置:

Java多线程基础

Java多线程是Java语言中的一项重要特性。多线程允许程序并发执行多个任务,让程序能够更高效地利用计算资源和提高相应速度。本文将从多个方面阐述Java多线程基础,包括线程创建、状态转换、同步与锁、线程池等。

一、线程创建

Java多线程的创建有两种方式:继承Thread类和实现Runnable接口。推荐使用实现Runnable接口的方式,因为这种方式可以更好地遵循面向对象设计原则,以及可以避免Java不支持多重继承的问题。

1. 继承Thread类

public class MyThread extends Thread {
    public void run() {
        //  这里放置线程需要执行的代码
    }
}

// 创建线程实例并启动
MyThread myThread = new MyThread();
myThread.start();

上述代码定义了一个线程类MyThread,重写了父类Thread中的run()方法,该方法中存放了线程需要执行的方法。创建线程实例后,调用start()方法启动线程。需要注意的是,直接调用run()方法不会启动一个新的线程,而是在当前线程中执行run()方法。

2. 实现Runnable接口

public class MyRunnable implements Runnable {
    public void run() {
        //  这里放置线程需要执行的代码
    }
}
// 创建线程实例并启动
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

上述代码定义了一个实现了Runnable接口的线程类MyRunnable。创建线程实例时,传入实例化的MyRunnable对象,并调用该线程的start()方法启动线程。

二、线程状态转换

线程在执行的过程中会发生状态,常见的状态有5种:新建状态、可运行状态、阻塞状态、等待状态、终止状态。线程状态转换如下:

1. 线程状态获取

线程状态可以使用getState()方法获得。该方法返回一个Thread.State枚举值,该枚举中定义了线程的所有状态。示例代码如下:

Thread thread = new Thread(() -> {
    //  执行任务
});
thread.start();
Thread.State state = thread.getState();   // 获取线程状态

2. 线程状态转换演示

通过以下代码,可以演示线程状态的转换过程:

public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"线程已启动");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"线程已结束");
        });
        System.out.println(t.getName()+" 线程状态:"+t.getState()); // NEW
        t.start();
        System.out.println(t.getName()+" 线程状态:"+t.getState()); // RUNNABLE
        Thread.sleep(500);
        System.out.println(t.getName()+" 线程状态:"+t.getState()); // TIMED_WAITING
        Thread.sleep(1000);
        System.out.println(t.getName()+" 线程状态:"+t.getState()); // TERMINATED
    }
}

运行结果:

Thread-0 线程状态:NEW
Thread-0 线程状态:RUNNABLE
Thread-0 线程状态:TIMED_WAITING
Thread-0 线程状态:TERMINATED

三、同步与锁

在多线程运行中,可能存在多个线程同时访问共享资源的情况,会导致数据不一致的问题。为了避免这种情况,需要使用同步与锁机制。

1. synchronized同步

synchronized是一种保证线程安全的机制,它可以修饰方法和代码块。在方法上添加synchronized关键字,可以实现对整个方法的同步。

public synchronized void synchronizedMethod() {
    //  synchronize方法体
}

在代码块上添加synchronized关键字,可以实现对指定代码块的同步。

public void method(){
    synchronized(this){
        //  synchronize代码块
    }
}

2. Lock锁机制

Lock是JDK提供的另一种线程同步机制,相比synchronized,Lock锁更加灵活,能够实现更细粒度的锁定。一个Lock锁可以同时被多个线程持有,线程使用完后必须释放锁。

Lock lock = new ReentrantLock();
lock.lock();   //  上锁
try {
    //  lock代码块
} finally {
    lock.unlock();  //  释放锁
}

四、线程池

在进行多线程编程时,经常使用线程池来提高执行效率。Java语言提供了线程池的支持,可以充分利用CPU,提高程序的执行效率。

1. ThreadPoolExecutor

ThreadPoolExecutor是Java中的线程池实现,它可以自动管理和调度线程,并且可以实现线程池定制化,非常灵活。以下是ThreadPoolExecutor的构造函数:

ThreadPoolExecutor(
    int corePoolSize,        //  线程池中核心线程数
    int maximumPoolSize,    //  线程池中最大线程数
    long keepAliveTime,     //  非核心线程空闲时间
    TimeUnit unit,          //  keepAliveTime的单位
    BlockingQueue workQueue,   //  任务队列
    ThreadFactory threadFactory,         //  线程工厂
    RejectedExecutionHandler handler      //  任务被拒绝时的处理方式
)

  

2. 线程池示例

以下代码演示了如何使用线程池实现多线程:

ExecutorService executorService = Executors.newFixedThreadPool(5);
for(int i = 0; i < 10; i++) {
    executorService.execute(() -> {
        //  执行任务
    });
}
executorService.shutdown();

以上代码创建了一个FixedThreadPool类型的线程池,指定了线程池中核心线程数为5,最大线程数为5,当线程空闲时间达到1秒时,非核心线程将被回收。线程池接受10个任务,通过execute()方法执行任务,线程池在执行完任务后将被关闭。

总结

本文介绍了Java多线程的基础知识,包括线程的创建、状态转换、同步与锁、线程池等方面。通过学习和实践,可以更好地掌握Java多线程编程。