Java初学者必备:线程基础概念详解

发表时间: 2024-06-08 12:31

线程

  • 线程(Thread)是一个程序内部一条执行路径
  • 多线程指从硬件上实现执行多条流程的技术

线程创建

  • 方式一:继承Thread类

① 编码简单

② 线程类已继承Thread类,无法再继承其他类,不便于扩展,线程有执行结果不可以直接返回

public class ThreadDemo {    public static void main(String[] args) {        // 创建线程对象        Thread t = new MyThread();        // 启动线程        t.start();    }}/** * 定义线程类继承Thread,重写run方法 */class MyThread extends Thread {    @Override    public void run() {        System.out.println("线程执行");    }}
  • 方式二:实现Runnable接口(匿名内部类形式)

① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展

多一层对象包装,线程有执行结果不可以直接返回

public class ThreadDemo2 {    public static void main(String[] args) {        // 创建任务对象        Runnable target = new MyRunnable();        // 任务对象交给Thread        Thread t = new Thread(target);        // 启动线程        t.start();        // 匿名内部类实现方式-1        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("执行线程-匿名内部类1");            }        }).start();        // 匿名内部类实现方式-2        new Thread(() -> {                System.out.println("执行线程-匿名内部类2");        }).start();    }}/** * 定义任务类,实现Runnable接口 */class MyRunnable implements Runnable {    /**     * 重写run方法     */    @Override    public void run() {        System.out.println("执行线程");    }}
  • 方式三:实现Callable接口

① 线程任务类只是实现接口,可以继续继承类和实现接口,便于扩展

② 可以在线程执行完成后获取结果

③ 编码稍微复杂

import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;public class ThreadDemo3 {    public static void main(String[] args) {        // 创建任务对象        Callable<String> callable = new MyCallable();        // Callable任务对象交给FutureTask对象,该对象是Runnable的对象        FutureTask<String> f = new FutureTask<>(callable);        // 给Thread线程处理        Thread t = new Thread(f);        // 启动线程        t.start();        // 获取结果        try {            String res = f.get();            System.out.println(res);        } catch (Exception e) {            e.printStackTrace();        }    }}/** * 定义任务类,实现Callable接口, 声明结果类型 */class MyCallable implements Callable<String> {    /**     * 重写call方法     */    @Override    public String call() throws Exception {        return "执行线程";    }}

线程安全

  • 多个线程同时写同一共享资源,可能会出现业务安全问题,称为线程安全

线程同步

  • 解决线程安全问题
  • 核心思想:加锁,对共享资源进行加锁,同时只能一个线程操作,完成后释放锁
  • 锁对象唯一

① 使用共享资源作为锁对象

② 实例方法使用this作为锁对象

③ 静态方法使用类名.class作为锁对象

  • 加锁方式

① 同步代码块,使用synchronized进行加锁,把出现线程安全问题的核心代码块加锁

② 同步方法,使用synchronized进行加锁,把出现线程安全问题的核心方法加锁

③ Lock锁

class SafeLock {    public final Lock lock = new ReentrantLock();    public void draw() {        // 加锁        lock.lock();        try {            System.out.println("逻辑处理");        } finally {            // 释放锁            lock.unlock();        }    }}

线程池

  • 可以复用线程的技术
  • 解决不断创建新线程问题,提高效率
  • 线程池实现API、参数说明

ThreadPoolExecutor构造器参数说明配图

  • 线程池处理Runnable任务
import java.util.concurrent.*;public class ThreadPoolDemo1 {    public static void main(String[] args) {        // 创建线程池对象        ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());        // 任务对象        Runnable target = new MyRunnablePool();        // 线程池处理任务        pool.execute(target);    }}/** * Runnable任务 */class MyRunnablePool implements Runnable{    @Override    public void run() {        System.out.println(Thread.currentThread().getName()+" 线程任务执行");    }}
  • 线程池处理Callable任务
import java.util.concurrent.*;public class ThreadPoolDemo2 {    public static void main(String[] args) {        // 创建线程池对象        ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());        // 线程池处理任务        Future<String> f = pool.submit(new MyCallablePool());        Future<String> f1 = pool.submit(new MyCallablePool());        Future<String> f2 = pool.submit(new MyCallablePool());        Future<String> f3 = pool.submit(new MyCallablePool());        try {            System.out.println(f.get());            System.out.println(f1.get());            System.out.println(f2.get());            System.out.println(f3.get());        } catch (Exception e) {            e.printStackTrace();        }    }}/** * Runnable任务 */class MyCallablePool implements Callable<String> {    @Override    public String call() throws Exception {        return Thread.currentThread().getName()+" 线程任务执行";    }}
  • Executors工具类线程池,大型并发系统可能出现系统风险,内存溢出
public class ThreadPoolDemo3 {    public static void main(String[] args) {        // 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。        ExecutorService pool = Executors.newFixedThreadPool(3);        pool.execute(new MyRunnableExecutorPool());        // 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。        ExecutorService pool1 = Executors.newSingleThreadExecutor();        pool1.execute(new MyRunnableExecutorPool());    }}/** * Runnable任务 */class MyRunnableExecutorPool implements Runnable{    @Override    public void run() {        System.out.println(Thread.currentThread().getName()+" 线程任务执行");    }}
  • 创建线程池

① 方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

② 方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象


定时器

  • 控制任务延时调用或周期调用的技术
  • 定时器的方式

① 方式一:Timer定时器

-Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入

-可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行

② 方式二:ScheduledExecutorservice定时器

-基于线程池,某个任务的执行情况不会影响其他定时任务的执行

public class TImerDemo2 {    public static void main(String[] args) {        // 创建定时器对象        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);        // 开启定时任务        pool.scheduleAtFixedRate(new TimerTask() {            @Override            public void run() {                System.out.println(Thread.currentThread().getName() +"执行a");                try {                    Thread.sleep(10000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, 0, 2, TimeUnit.SECONDS);                pool.scheduleAtFixedRate(new TimerTask() {            @Override            public void run() {                System.out.println(Thread.currentThread().getName() +"执行b");            }        }, 0, 2, TimeUnit.SECONDS);    }}

线程并发、并行

  • 并发

① CPU同时处理线程的数量有限

② CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,感觉这些线程在同时执行,这就是并发

  • 并行

① 在同一个时刻上,同时多个线程在被CPU处理并执行

生命周期

  • 线程状态,线程的状态:也就是线程从生到死的过程,以及中间经历的各种状态及状态转换

线程状态转换说明配图