多线程入门(自用)

1.概念

  • 基本概念
    • 程序是指令和数据的有序集合,其本身 没有任何运行的含义,是一个静态的概念
    • 而进程祖师执行程序的一次执行过程,它是一个动态的概念.是系统资源分配额单位
    • 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义.线程是cpu调度和执行的单位
    • 注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器.如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换得很快,所有就有同时执行的错觉
  • 核心概念
    • 线程就是独立的执行路径
    • 在程序运行时,即使没有自己 创建线程,后台也会有多个线程,如主线程,gc线程
    • main()称之为主线程,为系统的入口,用于执行整个程序
    • 在一个进程中,如果开辟了多个线程,线程的运行有调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
    • 对同一份资源操作是,会存在资源抢夺的问题,需要加入并发控制
    • 线程会带来额外的开销,如cpu调度时间,并发控制开销
    • 每个线程都在自己的工作内存交互,内存控制不当会造成数据不一致

三种创建方式

  • Thread class 继承Thread class 类(重点)
  • Runnable接口 实现Runnnable接口(重点)
  • Callable接口 实现Callable接口(了解)

在这里插入图片描述

2.继承Thread类

线程不一定立即执行,cpu安排调度

package study;

//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由cpu调度执行
public class Demo extends Thread {
    
    

	@Override
	public void run() {
    
    
		for (int i = 0; i < 200; i++) {
    
    
			System.out.println("run方法执行" + i);
		}
	}

	public static void main(String[] args) {
    
    
//		创建一个线程对象
		Demo s = new Demo();

//		调用start方法开启线程
		s.start();

		for (int i = 0; i < 800; i++) {
    
    
			System.out.println("main方法执行" + i);
		}
	}

}

网图下载

package study;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import org.apache.commons.io.FileUtils;

//练习Thread,实现多线程同步下载图片
public class Demo extends Thread {
    
    
	private String url;
	private String name;

	public Demo(String url, String name) {
    
    

		this.url = url;
		this.name = name;
	}

//下载图片线程的执行体
	@Override
	public void run() {
    
    
		WeDownloader weDownloader = new WeDownloader();
		weDownloader.downloader(url, name);
		System.out.println("下载了文件名为" + name);
	}

	public static void main(String[] args) {
    
    
		Demo d1 = new Demo("https://avatar.csdnimg.cn/E/F/0/1_qq_34509897_1616259578.jpg", "1.jpg");
		Demo d2 = new Demo("https://csdnimg.cn/medal/[email protected]", "002.png");
		Demo d3 = new Demo("https://csdnimg.cn/medal/[email protected]", "003.png");
//下载顺序并不是按照d1,d2,d3
		d1.start();
		d2.start();
		d3.start();
	}
}

//下载器
class WeDownloader {
    
    
//	下载方法
	public void downloader(String url, String name) {
    
    
		try {
    
    
			FileUtils.copyURLToFile(new URL(url), new File(name));
		} catch (IOException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("IO异常,downloader方法出现问题");
		}
	}
}

3.实现Runnable接口

package study;
//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法

public class Demo implements Runnable {
    
    

	@Override
	public void run() {
    
    
		for (int i = 0; i < 200; i++) {
    
    
			System.out.println("run方法执行" + i);
		}
	}

	public static void main(String[] args) {
    
    
//		创建runnable接口的实现类对象
		Demo demo = new Demo();

//		创建线程对象,通过线程对象来开启我们的线程,代理
//		Thread thread = new Thread(demo);
//		thread.start();
		new Thread(demo).start();
		for (int i = 0; i < 500; i++) {
    
    
			System.out.println("main方法执行" + i);
		}
	}
}

在这里插入图片描述

  • 初识并发问题
package study;
//多个线程同时操作同一个对象 

//买火车票例子

public class Demo implements Runnable {
    
    
//	票数
	private int ticketNums = 10;

	@Override
	public void run() {
    
    
		while (true) {
    
    
			if (ticketNums <= 0) {
    
    
				break;
			}
			try {
    
    
//				模拟延时
				Thread.sleep(200);
			} catch (InterruptedException e) {
    
    
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
//			currentThread返回当前线程
			System.out.println(Thread.currentThread().getName() + "--->拿到了第" + ticketNums-- + "张票");

		}
	}

	public static void main(String[] args) {
    
    
		Demo demo = new Demo();
		new Thread(demo, "张三").start();
		new Thread(demo, "李四").start();
		new Thread(demo, "王五").start();
	}
}

发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱

在这里插入图片描述

  • 模拟龟兔赛跑
package study;

//模拟龟兔赛跑
public class Demo implements Runnable {
    
    
//	胜利者
	private static String winner = null;

	@Override
	public void run() {
    
    
		boolean flag = false;
		for (int i = 0; i <= 100; i++) {
    
    
			flag = gameOver(i);
			if (flag) {
    
    
				break;
			}
			System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");

		}
	}

//判断是否结束比赛
	private boolean gameOver(int steps) {
    
    
//如果步数为100,则判断为胜利者
		if (steps == 100) {
    
    
			winner = Thread.currentThread().getName();
			System.out.println("winner is" + winner);
			return true;
		}

		return false;
	}

	public static void main(String[] args) {
    
    
		Demo demo = new Demo();
		new Thread(demo, "兔子").start();
		new Thread(demo, "乌龟").start();
	}
}

4.实现Callable接口(了解接口)

  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(3);
  5. 提交执行 Future r1 = ser.submit(d1);
  6. 获取结果 boolean rs1 = r1.get();
  7. 关闭服务 ser.shutdown();

利用Callable改造下载图片案例:

package study;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.*;

import org.apache.commons.io.FileUtils;

/**
 * 线程创建方式三:实现Callable接口 1.可以定义返回值 2.可以抛出异常
 * 
 * @author badwoman
 *
 */
public class Demo implements Callable<Boolean> {
    
    
	private String url;
	private String name;

	public Demo(String url, String name) {
    
    

		this.url = url;
		this.name = name;
	}

//下载图片线程的执行体
	@Override
	public Boolean call() {
    
    
		WeDownloader weDownloader = new WeDownloader();
		weDownloader.downloader(url, name);
		System.out.println("下载了文件名为" + name);
		return true;
	}

	public static void main(String[] args) throws InterruptedException, ExecutionException {
    
    
		Demo d1 = new Demo("https://avatar.csdnimg.cn/E/F/0/1_qq_34509897_1616259578.jpg", "1.jpg");
		Demo d2 = new Demo("https://csdnimg.cn/medal/[email protected]", "002.png");
		Demo d3 = new Demo("https://csdnimg.cn/medal/[email protected]", "003.png");

//		创建执行服务
		ExecutorService ser = Executors.newFixedThreadPool(3);

		// 提交执行
		Future<Boolean> r1 = ser.submit(d1);
		Future<Boolean> r2 = ser.submit(d2);
		Future<Boolean> r3 = ser.submit(d3);

//		获取结果
		boolean rs1 = r1.get();
		boolean rs2 = r2.get();
		boolean rs3 = r3.get();

//		关闭服务
		ser.shutdown();
	}

}

//下载器
class WeDownloader {
    
    
//	下载方法
	public void downloader(String url, String name) {
    
    
		try {
    
    
			FileUtils.copyURLToFile(new URL(url), new File(name));
		} catch (IOException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("IO异常,downloader方法出现问题");
		}
	}
}

5.静态代理模式

package study;

/**
 * 静态代理模式总结: 真实对象和代理对象都要同时实现一个接口
 *  代理对象要代理真实角色
 * 
 * @author badwoman
 *
 */
public class Demo {
    
    
	public static void main(String[] args) {
    
    
//		lamda表达式
		new Thread(() -> System.out.println("我爱你")).start();
		new WeddingCompant(new You()).HappyMarry();
	}
}

interface Marry {
    
    
	// 结婚事件
	void HappyMarry();
}

//这是结婚角色
class You implements Marry {
    
    
	@Override
	public void HappyMarry() {
    
    
		System.out.println("xx要结婚了");

	}
}

//代理角色,帮助结婚
class WeddingCompant implements Marry {
    
    
	// 代理真实目标角色
	private Marry target;

	public WeddingCompant(Marry target) {
    
    

		this.target = target;
	}

	@Override
	public void HappyMarry() {
    
    
		before();
		this.target = target;// 真实对象
		after();
	}

	private void before() {
    
    
		System.out.println("结婚之前");
	}

	private void after() {
    
    
		System.out.println("结婚之后");
	}

}

6.lamda表达式

  • 理解Functional Interface(函数式接口)是学习java8 lambda表达式的关键所在
  • 函数式接口的定义:
    • 只包含唯一一个抽象方法的接口
    • 对于 函数式接口,我们可以通过lambda表达式来创建该接口的对象
package study;

/**
 * lambda表达式只能有一行的代码的情况下才能简化成为一行,如果有多行,则用代码块包裹
 * 前提是接口为函数式接口
 * 多个参数也可以去掉参数类型,要去掉就全部去掉,而且不想加上括号
 * @author badwoman
 *
 */
public class Demo {
    
    

	public static void main(String[] args) {
    
    

		ILike like = a -> System.out.println(a);

		like.love(5);
	}

}

interface ILike {
    
    
	void love(int a);
}

7.线程状态

五大状态:

在这里插入图片描述

  • 停止线程

在这里插入图片描述

package study;

import java.util.Iterator;

public class Demo implements Runnable {
    
    
//	1.设置一个标识符
	private boolean flag = true;

	@Override
	public void run() {
    
    
		int i = 0;
		while (flag) {
    
    
			System.out.println("run...Thread" + i++);
		}
	}

//	2.设置一个公开的方法停止线程,转换标志位
	public void stop() {
    
    
		this.flag = false;
	}

	public static void main(String[] args) {
    
    
		Demo demo = new Demo();
		new Thread(demo).start();
		for (int i = 0; i < 200; i++) {
    
    
			System.out.println("main" + i);
			if (i == 100) {
    
    
				demo.stop();
				System.out.println("该线程停止了");
			}
		}
	}
}
  • 线程休眠
    • sleep时间达到后线程进入就绪状态
    • 每一个对象都有一个锁,sleep不会释放锁
package study;

import java.sql.Date;
import java.text.SimpleDateFormat;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
		Date date = new Date(System.currentTimeMillis());
//		打印当前系统时间
		while (true) {
    
    
			try {
    
    
				Thread.sleep(1000);
				System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
				date = new Date(System.currentTimeMillis());
			} catch (InterruptedException e) {
    
    
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}

		}
	}
}
  • 线程礼让

    • 让当前正在执行的线程暂停,但不阻塞

    • 将线程从运行状态转为就绪状态

    • 让cpu重新调度,礼让不一定成功!看cpu心情

    • Thread.yield();礼让
      
  • join

    • join合并线程,待次线程执行完成后,在执行其他线程,其他线程阻塞
    • 可以想象成插队
package study;

public class Demo implements Runnable {
    
    
	@Override
	public void run() {
    
    
		for (int i = 0; i < 500; i++) {
    
    
			System.out.println("线程VIP来了" + i);
		}
	}

	public static void main(String[] args) throws InterruptedException {
    
    
//		启动线程
		Demo demo = new Demo();
		Thread thread = new Thread(demo);
		thread.start();

		for (int i = 0; i < 200; i++) {
    
    
			if (i == 100) {
    
    
				thread.join();
			}
			System.out.println("main" + i);
		}
	}
}
  • 线程状态观测
package study;

import java.lang.Thread.State;

public class Demo {
    
    
	public static void main(String[] args) throws InterruptedException {
    
    
		Thread thread = new Thread(()->{
    
    
		for (int i = 0; i <=5; i++) {
    
    
			try {
    
    
				Thread.sleep(1000);
			} catch (InterruptedException e) {
    
    
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			System.out.println("----------");
		}
		});
//		观测状态
		State state = thread.getState();
		System.out.println(state);
		
//		观测启动后
		thread.start();//启动线程
		state = thread.getState();
		System.out.println(state);

		while (state!=thread.getState().TERMINATED) {
    
    
			thread.sleep(100);
			state = thread.getState();
			System.out.println(state);
		}
//		thread.start();  再次启动线程会报错,原因:线程死亡后不能再次启动
	}
}

8.线程优先级

在这里插入图片描述

package study;

public class Demo implements Runnable{
    
    
	public static void main(String[] args)  {
    
    
		//主线程默认优先级
//		getPriority获得当前优先级
		System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
		Demo demo = new Demo();
		Thread t1=new Thread(demo);
		Thread t2=new Thread(demo);
		Thread t3=new Thread(demo);
		Thread t4=new Thread(demo);
		Thread t5=new Thread(demo);
		Thread t6=new Thread(demo);
//		先设置优先级在启动
		t1.setPriority(7);
		t2.setPriority(2);
		t3.setPriority(1);
		t4.setPriority(6);
		t5.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
		t6.setPriority(3);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
	}

	@Override
	public void run() {
    
    
		System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
	}
}

9.守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕
  • 用户线程:main() 守护线程:后台记录操作日志,监控内存,垃圾回收等待
package study;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
		Thread thread = new Thread(new Test2());
		thread.setDaemon(true);//默认是false表示是用户线程,true表示是守护线程
		thread.start();
		new Thread(new Test1()).start();

	}
}

class Test1 implements Runnable {
    
    
	@Override
	public void run() {
    
    
		for (int i = 0; i < 100; i++) {
    
    
			System.out.println("用户线程执行" + i);
		}
		System.out.println("用户线程结束");
	}
}

class Test2 implements Runnable {
    
    
	@Override
	public void run() {
    
    
		while (true) {
    
    
			System.out.println("守护线程执行");
		}
	}
}

10.线程同步机制

在这里插入图片描述
在这里插入图片描述

11.三大不安全案例

package study;

//不安全买票
//问题:出现两个拿到同一张票
//修改: 添加synchronize 把买票设置为同步方法,锁的是对象
public class Demo {
    
    
	public static void main(String[] args) {
    
    
		BuyTicket satrtion = new BuyTicket();
		new Thread(satrtion, "张三").start();
		;
		new Thread(satrtion, "李四").start();
		;
		new Thread(satrtion, "王五").start();
		;
	}
}

class BuyTicket implements Runnable {
    
    
	private int ticketNums = 10;
	boolean flag = true;// 外部停止方式

	@Override
	public void run() {
    
    

		// 买票
		while (flag) {
    
    
			try {
    
    
				Thread.sleep(1000);
			} catch (InterruptedException e) {
    
    
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			buy();
		}
	}

	private synchronized void buy() {
    
    
//		判断是否有票
		if (ticketNums <= 0) {
    
    
			flag = false;
			return;
		}
		// 买票
		System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
	}
}
package study;

//不安全取钱
//两个人去银行取钱
//问题:银行余额出现负数
//修改:使用同步块锁需要增删改的对象
public class Demo {
    
    
	public static void main(String[] args) {
    
    
		Account account = new Account(100, "基金");

		Drawing father = new Drawing(account, 50, "父亲");
		Drawing mother = new Drawing(account, 100, "母亲");
		father.start();
		mother.start();
	}
}

//账户
class Account {
    
    
	int money;// 余额
	String name;// 卡名

	public Account(int money, String name) {
    
    

		this.money = money;
		this.name = name;
	}
}

//银行:模拟存款
class Drawing extends Thread {
    
    
	Account account;// 账户
	int drawingMoney;// 取了多少钱
	int nowMoney;

	public Drawing(Account account, int drawingMoney, String name) {
    
    
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;

	}

	// 取钱
	@Override
	public  void run() {
    
    
		synchronized (account) {
    
    
//			判断有没有钱
			if (account.money - drawingMoney < 0) {
    
    

				System.out.println(Thread.currentThread().getName() + "钱不够了取不了");
				return;
			}
			try {
    
    
				Thread.sleep(1000);
			} catch (InterruptedException e) {
    
    
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
//			卡内余额
			account.money -= drawingMoney;
//			手里的钱
			nowMoney += drawingMoney;

			System.out.println(account.name + "余额为" + account.money);
			System.out.println(this.getName() + "手里的钱" + nowMoney);
		}
	}

}
package study;

import java.util.ArrayList;
import java.util.List;

//问题:长度不能填满集合
//修改:使用同步块
public class Demo {
    
    
	public static void main(String[] args) {
    
    
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < 10000; i++) {
    
    
			new Thread(() -> {
    
    
				synchronized (list) {
    
    
					list.add(Thread.currentThread().getName());
				}
			}).start();
			;
		}
		try {
    
    
			Thread.sleep(3000);
		} catch (InterruptedException e) {
    
    
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		System.out.println(list.size());
	}
}

总结:

  • synchronized默认锁的是当前类对象
  • 我们需要说的对象是变化的量,需要增删改的对象

12.补充: 线程安全的集合

package study;
//不需要添加锁
import java.util.concurrent.CopyOnWriteArrayList;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
		CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
		for (int i = 0; i < 10000; i++) {
    
    
			new Thread(()->{
    
    
				list.add(Thread.currentThread().getName());
			}).start();
		}
		try {
    
    
			Thread.sleep(3000);
		} catch (InterruptedException e) {
    
    
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		System.out.println(list.size());
	}
}

13.死锁

在这里插入图片描述

错误示范:

由于两人同时想获得对方的锁,但又不放开已经获得的锁,造成程序停止

package study;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
		Makeup girl1 = new Makeup(0,"girl1");
		Makeup girl2 = new Makeup(1,"girl12");
		girl1.start();
		girl2.start();
	}
}

//口红
class Lipstick {
    
    

}

//镜子
class Mirror {
    
    

}

class Makeup extends Thread {
    
    
	// 需要的资源只有一份,用static来保证只有一份
	static Lipstick lipstick = new Lipstick();
	static Mirror mirror = new Mirror();

	int choice;// 选择
	String girl;// 使用化妆品的人

	public Makeup(int choice, String girl) {
    
    

		this.choice = choice;
		this.girl = girl;
	}

	@Override
	public void run() {
    
    
		try {
    
    
			makeup();
		} catch (InterruptedException e) {
    
    
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}

	private void makeup() throws InterruptedException {
    
    
		if (choice == 0) {
    
    
			synchronized (lipstick) {
    
    
				System.out.println(this.girl + "获得口红的锁");
				Thread.sleep(1000);
				synchronized (mirror) {
    
    
					System.out.println(this.girl + "获得镜子的锁");
				}
			}
		} else {
    
    
			synchronized (mirror) {
    
    
				System.out.println(this.girl + "获得镜子的锁");
				Thread.sleep(3000);
				synchronized (lipstick) {
    
    
					System.out.println(this.girl + "获得口红的锁");
				}
			}
		}
	}
}

修改后:

package study;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
		Makeup girl1 = new Makeup(0, "girl1");
		Makeup girl2 = new Makeup(1, "girl12");
		girl1.start();
		girl2.start();
	}
}

//口红
class Lipstick {
    
    

}

//镜子
class Mirror {
    
    

}

class Makeup extends Thread {
    
    
	// 需要的资源只有一份,用static来保证只有一份
	static Lipstick lipstick = new Lipstick();
	static Mirror mirror = new Mirror();

	int choice;// 选择
	String girl;// 使用化妆品的人

	public Makeup(int choice, String girl) {
    
    

		this.choice = choice;
		this.girl = girl;
	}

	@Override
	public void run() {
    
    
		try {
    
    
			makeup();
		} catch (InterruptedException e) {
    
    
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}

	private void makeup() throws InterruptedException {
    
    
		if (choice == 0) {
    
    
			synchronized (lipstick) {
    
    
				System.out.println(this.girl + "获得口红的锁");
				Thread.sleep(1000);

			}
			synchronized (mirror) {
    
    
				System.out.println(this.girl + "获得镜子的锁");
			}
		} else {
    
    
			synchronized (mirror) {
    
    
				System.out.println(this.girl + "获得镜子的锁");
				Thread.sleep(3000);

			}
			synchronized (lipstick) {
    
    
				System.out.println(this.girl + "获得口红的锁");
			}
		}
	}
}

14.Lock锁

在这里插入图片描述

package study;

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

public class Demo {
    
    

	public static void main(String[] args) {
    
    
		Makeup girl1 = new Makeup(0, "girl1");
		Makeup girl2 = new Makeup(1, "girl12");
		girl1.start();
		girl2.start();
	}
}

//口红
class Lipstick {
    
    

}

//镜子
class Mirror {
    
    

}

class Makeup extends Thread {
    
    
	// 需要的资源只有一份,用static来保证只有一份
	static Lipstick lipstick = new Lipstick();
	static Mirror mirror = new Mirror();

	int choice;// 选择
	String girl;// 使用化妆品的人

	public Makeup(int choice, String girl) {
    
    

		this.choice = choice;
		this.girl = girl;
	}

	@Override
	public void run() {
    
    
		try {
    
    
			makeup();
		} catch (InterruptedException e) {
    
    
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}

	private void makeup() throws InterruptedException {
    
    
		final ReentrantLock lock = new ReentrantLock();// 定义锁
		if (choice == 0) {
    
    
			lock.lock();// 上锁
			System.out.println(this.girl + "获得口红的锁");
			lock.unlock();// 解锁
			Thread.sleep(1000);

			System.out.println(this.girl + "获得镜子的锁");

		} else {
    
    
			lock.lock();
			System.out.println(this.girl + "获得镜子的锁");
			lock.unlock();
			Thread.sleep(3000);

			System.out.println(this.girl + "获得口红的锁");

		}
	}
}

15.线程池

在这里插入图片描述

package study;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
    
    
	public static void main(String[] args) {
    
    
//		1.创建服务,创建线程池
//		参数为:线程池大小
		ExecutorService service = Executors.newFixedThreadPool(10);
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());

//		2.关闭链接
		service.shutdown();
	}

}

class MyThread implements Runnable {
    
    
	@Override
	public void run() {
    
    
		System.out.println(Thread.currentThread().getName());
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34509897/article/details/116924960