多线程和线程池

本文深入探讨多线程的概念,包括线程与进程的区别、线程的创建与执行、线程状态与调度、线程同步与死锁、以及线程池的使用。通过实例演示如何利用Java实现多线程,提高程序效率。

多线程

同时运行了多个线程,用来完成不同的工作

多个线程交替CPU资源

好处:

充分利用CPU的资源

简化编程模型

带来良好的用户体验

进程和线程的区别

进程

应用程序的执行实例-》进程《-有独立的内存空间和系统资源

线程

CPU调度和分派的基本单位-》线程《-进程中执行运算的最小单位,可完成一个独立的顺序控制流程

主线程

​ java.lang.Tread类支持多线程

​ main()方法即主线程入口
在这里插入图片描述

实现Runnable接口创建线程

  • 自定义Thread类末尾要加Thread
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动多线程

在main方法里直接调用run()方法只执行一个线程main(单线程),一个执行完在执行一个。

start()方法是多线程交替执行(CPU分配时间片)

继承Thread类

  • 编写简单,可直接操作线程
  • 是用于单根继承

实现Runnable接口

  • 避免单继承局限性
  • 便于共享资源

线程的状态和线程的调度

在这里插入图片描述

线程的五个状态

创建、就绪、阻塞、运行、死亡

线程调度的方法

setPriority(int grade) 优先级调整

// 获得当前线程名
Thread.currentThread().getName();
// 线程优先级最高
setPriority(Thread.MAX_PRIORITY);
// 线程优先级最低
setPriority(Thread.MIN_PRIORITY);

​ sleep(long millis) 线程休眠

Thread.sleep(1000); // 休眠1000毫秒

​ join() 线程强制执行使该线程先执行完毕

​ yield()优先级默认5 由1-10表示让线程暂时书面指定时常,线程进入阻塞状态

public static void main(String[] args) {
		System.out.println("*************线程强制执行*************");
		// 1.创建线程对象
		Thread temp = new Thread(new MyRunnable3(),"temp");
		temp.start();
		for (int i = 0; i < 20; i++) {
			// 当主线程执行到i==5时,暂停主线程,让子线程temp执行完毕之后,主线程再执行
			if (i==5) {
				try {
					temp.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
dSystem.out.println(Thread.currentThread().getName()+"运行:"+i);
		}

线程的礼让yield();暂停当前线程,允许其他具有相同优先级的线程获得运行的机会。

该线程处于就绪状态,不转为阻塞状态

该礼让不一定会实现

线程的同步

使用synchronized修饰的方法控制对类成员变量的访问

可以放在访问修饰符前面或后面

synchronized就是为当前线程声明一个锁

使用synchronized关键字修饰的代码块

synchronized (this) {
    while(true) {
        if (count <= 0) {
            break;
        }
        // 1.修改数据(剩余票数、抢到第几张票)
        count--;
        num++;
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 2.显示信息,反馈用户抢到第几张票
        System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,"+"剩余第"+count+"张票");

}
多个并发线程访问同一资源的同步代码块时
  • 同一时刻只能有一个线程进入synchronized(this)同步代码块
  • 当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
  • 当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问非synchronized(this)同步代码
StringBuffer是同步的,StringBuilder非同步
HashTable是同步的,HashMap是非同步的
一般同步的用于多线程,非同步用于单线程

1556770509739

死锁

死锁-两个线程都在等待对方先完成,造成程序的停滞
死锁条件
  • 两个或两个以上的线程在活动

  • 某个线程拿到一个锁以后,还想拿第二个锁,造成所得嵌套

线程池

executors工具类

缓存线程池
public class ThreedPool {
	public static void main(String[] args) {
		ExecutorService es = Executors.newCachedThreadPool();
		
		// 在线程池中执行10个任务
		for (int i = 0; i < 10; i++) {
			es.execute(new MyRunnable(i));
		}
	}
}

class MyRunnable implements Runnable{
	int num;
	public MyRunnable(int num) {
		super();
		this.num = num;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+":"+num);
	}
	
}

单线程池
public class ThreedPool {
	public static void main(String[] args) {
		ExecutorService es = Executors.newSingleThreadExecutor();
		
		// 在单线程池中执行任务
		for (int i = 0; i < 10; i++) {
			es.execute(new MyRunnable(i));
		}
	}
}

class MyRunnable implements Runnable{
	int num;
	public MyRunnable(int num) {
		super();
		this.num = num;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+":"+num);
	}
	
}

固定线程池
public class ThreedPool2 {
	public static void main(String[] args) {
		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
		
		// 在线程池中执行3个任务
		for (int i = 0; i < 10; i++) {
			fixedThreadPool.execute(new MyRunnable1(i));
		}
	}
}

class MyRunnable1 implements Runnable{
	int num;
	public MyRunnable1(int num) {
		super();
		this.num = num;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+":"+num);
	}
	
}
定时执行任务线程
public class ThreedPool3 {
	public static void main(String[] args) {
		ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
		System.out.println("**********开始执行************");
		ses.scheduleAtFixedRate(new MyRunnable2(), 5, 2, TimeUnit.SECONDS);
		
	}
}

class MyRunnable2 implements Runnable{
	int num;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"延时5s执行,每2s执行一次!");
	}
	
}
自定义线程
ublic class ThreadPool4 {
	public static void main(String[] args) {
		ThreadPoolExecutor tpe = new ThreadPoolExecutor(5,7,300,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(4));
		for (int i = 1; i <= 12; i++) {
			tpe.execute(new MyRunnable4(i));
			System.out.println("线程池中的线程数:"+tpe.getPoolSize()+"队列中等待执行的线程数:"+tpe.getQueue().size()
					+"已经执行完的线程数:"+tpe.getCompletedTaskCount());
		}
		tpe.shutdown();
	}
}
class MyRunnable4 implements Runnable{
	int num;
	public MyRunnable4(int num) {
		super();
		this.num = num;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("正在执行任务"+num);
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("任务"+num+"执行完毕!");
	}
}

在这里插入图片描述

序号名称类型含义
1corePoolSizeint核心线程池大小
2maximumPoolSizeint最大线程池大小
3keepAliveTimelong线程最大空闲时间
4unitTimeUnit时间单位
5workQueueBlockingQueue线程等待队列
6threadFactoryThreadFactory线程创建工厂
7handlerRejectedExecutionHandler拒绝策略
<think>嗯,用户问的是多线程线程池的区别。我需要先回顾一下这两个概念的基本定义。多线程通常指的是在应用程序中创建多个线程来同时执行不同的任务,而线程池则是一个管理多个线程的机制,根据需要分配任务给这些线程,避免频繁创建销毁线程的开销。 首先,用户可能对这两个概念有些混淆,或者想了解它们在实际应用中的不同。我需要从几个方面来对比,比如资源管理、性能、适用场景等。比如,多线程直接创建线程,资源消耗大,而线程池可以复用线程,减少开销。另外,线程池有任务队列管理策略,而多线程需要手动管理线程的生命周期。 接下来,用户可能想知道具体的应用场景。例如,线程池适合任务数量多且短小的情况,而多线程可能适合任务独立且数量较少的情况。需要举一些例子,比如Web服务器处理请求用线程池,而单个后台任务可能用多线程。 还要注意用户可能的误区,比如认为线程池只是简单的线程复用,但实际上它还有更多的管理功能,比如控制并发数、任务调度等。需要明确这些区别,帮助用户理解为何线程池更高效可靠。 另外,用户可能没有提到但需要补充的是,线程池如何避免资源耗尽的问题,比如通过拒绝策略队列管理,而多线程如果没有正确控制,可能导致系统资源被大量线程占用,甚至崩溃。 最后,要确保回答结构清晰,分点说明区别,并给出示例代码,帮助用户更直观地理解。同时,相关问题要围绕用户可能的后续疑问,比如线程池配置、任务队列选择、线程安全等,确保覆盖全面。</think>多线程线程池是并发编程中的两种不同实现方式,核心区别在于**资源管理方式****任务调度机制**。以下是具体对比: --- ### **1. 定义与核心区别** | **维度** | **多线程(直接创建线程)** | **线程池(ThreadPool)** | |------------------|--------------------------------------------------|--------------------------------------------------| | **实现方式** | 直接通过`new Thread().start()`创建线程并执行任务 | 通过线程池管理线程生命周期,任务提交后由池内线程动态分配执行 | | **资源消耗** | 频繁创建/销毁线程,导致资源浪费(如内存、CPU上下文切换) | 线程复用,减少资源开销 | | **任务调度** | 需手动管理线程同步、优先级、生命周期等 | 自动管理任务队列、线程分配、拒绝策略等 | | **适用场景** | 简单的短期任务或少量并发需求 | 复杂的高并发任务(如Web服务器、批量数据处理) | --- ### **2. 代码示例对比** #### **多线程直接创建线程** ```java new Thread(() -> { System.out.println("执行任务1"); }).start(); new Thread(() -> { System.out.println("执行任务2"); }).start(); ``` #### **线程池提交任务** ```java ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(() -> System.out.println("执行任务1")); executor.submit(() -> System.out.println("执行任务2")); executor.shutdown(); ``` --- ### **3. 关键区别详解** #### **(1)资源管理** - **多线程**: 每次任务都需要创建新线程,频繁的创建/销毁会导致内存CPU资源浪费,尤其在高并发场景下可能引发`OutOfMemoryError`。 - **线程池**: 通过线程复用机制减少资源开销。例如,核心线程数为5的线程池可复用5个线程处理100个任务。 #### **(2)任务调度控制** - **多线程**: 需手动实现线程同步(如`join()`、`synchronized`)优先级控制,容易引发死锁或资源竞争。 - **线程池**: 提供任务队列(如`BlockingQueue`)拒绝策略(如`AbortPolicy`),自动管理任务的排队执行。 #### **(3)稳定性与扩展性** - **多线程**: 无内置的限流熔断机制,任务过载时可能直接压垮系统。 - **线程池**: 可通过参数配置实现动态扩容(如`maximumPoolSize`)、任务排队(如`ArrayBlockingQueue`)拒绝策略(如记录日志或降级处理)。 #### **(4)适用场景** - **多线程**: 适合任务数量少、执行时间短、无需复杂管理的场景(如单次异步通知)。 - **线程池**: 适合高并发、任务量大、需精细化控制的场景(如HTTP请求处理、定时任务调度)。 --- ### **4. 线程池的优势总结** 1. **降低资源消耗**:通过复用线程减少创建/销毁的开销。 2. **提高响应速度**:任务到达后无需等待线程创建,直接执行。 3. **任务统一管理**:支持任务队列、拒绝策略、线程监控等。 4. **避免资源耗尽**:通过队列拒绝策略防止系统过载。 --- ### **5. 典型反例:直接使用多线程的风险** ```java for (int i = 0; i < 10000; i++) { new Thread(() -> { // 处理任务 }).start(); } ``` - **风险**: - 线程数超过系统承载能力,导致内存溢出(`OutOfMemoryError`)。 - CPU频繁切换线程上下文,性能急剧下降。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值