01线程简介
程序:指令和数据的有序集合,静态。
进程(Process):程序的一次执行过程,动态。是系统资源分配的单位。
线程(Thread):一个进程可包含若干线程。线程是cpu调度和执行的单位。
-
main()称之为主线程,为系统的入口,用于执行整个程序
-
每个线程在自己的工作内存交互,内存控制不当会造成数据的不一致
02线程创建
方法一:
-
自定义线程类继承Thread类
-
重写run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动线程
//1.继承Thread类 public class MyThread extends Thread{ //2.重写run()方法 @Override public void run() { //run方法线程体 for (int i = 0; i < 20; i++) { System.out.println("线程执行体"+i); } } public static void main(String[] args) { //main线程,主线程 //3.创建线程对象,调用start()方法启动线程 MyThread myThread =new MyThread(); myThread.start(); //testThread1.run(); for (int i = 0; i < 20; i++) { System.out.println("主线程"+i); } } }
方法二(推荐):
-
自定义类实现Runnable接口
-
实现run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动线程
将实现Runnable接口的对象作为参数传入Thread对象的构造方法中
//1.实现Runnable接口 public class MyRunnable implements Runnable{ //2.实现run()方法 @Override public void run() { //run方法线程体 for (int i = 0; i < 20; i++) { System.out.println("线程执行体"+i); } } public static void main(String[] args) { //3。创建线程对象,调用start()方法启动线程 MyThread myThread=new MyThread(); Thread thread=new Thread(myThread); thread.start(); for (int i = 0; i < 20; i++) { System.out.println("主线程"+i); } } }
方法二便于同一个对象被多个线程使用
run()方法与start()方法区别:
run()方法顺序执行,start()方法并发执行
03并发问题
实现接口方法的快捷键:Alt+Enter try..catch...快捷键:Ctrl+Alt+T
买票
//多个线程同时操作同一个对象 //买票的例子 public class TicketThread implements Runnable{ //票数 private int ticketNums = 5; @Override public void run() { while(true){ if(ticketNums<=0) break; try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"张票"); } } public static void main(String[] args) { TicketThread ticket=new TicketThread(); new Thread(ticket,"小明").start(); new Thread(ticket,"老师").start(); new Thread(ticket,"黄牛").start(); } }
可能的结果:
如上图,第2张票同时被小明和黄牛拿到,出现并发问题
龟兔赛跑
//模拟龟兔赛跑:谁先跑到100步谁赢 public class Race implements Runnable{ private static String winner; private int steps; @Override public void run() { while(true) { //兔子睡觉 if(Thread.currentThread().getName()=="兔子"&&steps%10==0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } //flag判断是否有胜利者 boolean flag=gameOver(steps); if(flag) break; System.out.println(Thread.currentThread().getName()+"跑了"+(++steps)+"步"); } } public boolean gameOver(int steps){ //如果有winner了,就不会再有winner if(winner!=null) return true; if(steps>=100){ winner=Thread.currentThread().getName(); System.out.println("胜利者是"+winner); return true; } return false; } public static void main(String[] args) { //一条赛道 Race race=new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
04Lambda表达式
为什么要使用lambda表达式
-
避免匿名内部类定义过多
-
使代码简洁。去掉无意义代码,只留下核心逻辑
函数式接口:只包含一个抽象方法的接口
我们可以使用lambda表达式创建函数式接口的对象
lambda表达式是用于简化函数式接口
//推导lambda表达式 public class Lambda { //3.静态内部类 static class Like2 implements ILike { @Override public void lambda() { System.out.println("I like lambda2"); } } public static void main(String[] args) { //4.局部内部类 class Like3 implements ILike { @Override public void lambda() { System.out.println("I like lambda3"); } } ILike like=new Like1(); like.lambda(); like=new Like2(); like.lambda(); like=new Like3(); like.lambda(); //5.匿名内部类:没有类的名称,必须借助接口或者父类 like =new ILike() { @Override public void lambda() { System.out.println("I like lambda4"); } }; like.lambda(); //6.用lambda简化 like=()->{ System.out.println("I like lambda5"); }; like.lambda(); } } //1.定义一个函数式接口 interface ILike{ void lambda(); } //2.实现类 class Like1 implements ILike{ @Override public void lambda() { System.out.println("I like lambda1"); } }
Lambda表达式练习:
public class LambdaTest { public static void main(String[] args) { // ILove love=(String name)->{ // System.out.println("I love "+name); // }; //简化1:去掉参数类型 String // ILove love=(name)->{ // System.out.println("I love "+name); // }; //简化2:去掉括号:只有一个参数时才能去掉括号 // ILove love=name->{ // System.out.println("I love "+name); // }; //简化3:去掉{}:只有方法体中只有一行语句才可以去掉{} ILove love=name-> System.out.println("I love "+name); love.love("Z"); } } interface ILove{ void love(String name); }
05静态代理
-
真实对象和代理对象实现同一个接口
-
代理对象代理真实角色
-
好处:
-
代理对象可以做真实对象做不了的事情
-
真实对象可以专注做自己的事情
-
public class StaticProxy { public static void main(String[] args) { // Person person=new Person();//人要结婚 // WeddingCompany weddingCompany=new WeddingCompany(person);//婚庆公司代理 // weddingCompany.HappyMarray(); //线程对比静态代理 //new Thread(()-> System.out.println("我爱你")).start(); new WeddingCompany(new Person()).HappyMarray(); } } interface Marray{ void HappyMarray(); } //真实角色,男方 class Person implements Marray{ @Override public void HappyMarray() { System.out.println("男方正在结婚"); } } //代理角色,帮助男方去结婚 class WeddingCompany implements Marray{ //代理谁-->真实目标角色 private Marray target; public WeddingCompany(Marray target){ this.target=target; } @Override public void HappyMarray() { before(); this.target.HappyMarray();//真实对象 after(); } private void before() { System.out.println("结婚前,布置现场"); } private void after() { System.out.println("结婚后,收尾款"); } }
06线程状态
五大状态:
01线程停止:
//线程停止 //1.建议线程正常停止-->利用次数,不建议死循环 //2.建议使用标志位-->设置一个标志位flag public class ThreadStop implements Runnable{ //设置一个标志位 private boolean flag=true; @Override public void run() { if (flag){ System.out.println("线程体正在执行"); } } //设置停止线程执行的方法 public void stop(){ this.flag=false; } public static void main(String[] args) { ThreadStop threadStop=new ThreadStop(); new Thread(threadStop).start(); for (int i = 0; i < 100; i++) { if (i==99) threadStop.stop(); System.out.println("主线程执行--"+i); } } }
02线程休眠_sleep
-
sleep(时间)指定当前线程阻塞的毫秒数;
-
sleep存在InterruptedException异常;
-
sleep时间达到后线程进入就绪态;
-
sleep可以模拟网络延时,倒计时等。
-
每一个对象都有一个锁,sleep不会释放锁;
sleep模拟倒计时:
//模拟倒计时 public class ThreadSleep{ //模拟倒计时的方法 public static void tenDown(int num){ while(true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(num--); if(num<=0) break; } } public static void main(String[] args) { //3秒倒计时 tenDown(3); } }
03线程礼让_yield
-
让当前正在执行的线程暂停,但不阻塞
-
将线程从运行态转为就绪态
-
让CPU重新调度,礼让不一定成功
public class ThreadYield implements Runnable{ public static void main(String[] args) { ThreadYield threadYield=new ThreadYield(); new Thread(threadYield,"a").start(); new Thread(threadYield,"b").start(); } @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程开始运行"); Thread.yield();//线程礼让 System.out.println(Thread.currentThread().getName()+"线程运行结束"); } }
礼让成功:
礼让不成功:
04线程强制执行_join
-
join合并线程,待此线程执行完后,再执行其他线程,其他线程阻塞
-
“插队”
public class ThreadJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"线程来插队了"+i); } } public static void main(String[] args) throws InterruptedException { ThreadJoin threadJoin=new ThreadJoin(); Thread thread=new Thread(threadJoin,"插队"); thread.start(); //主线程 for (int i = 0; i < 10; i++) { if(i==5){ thread.join(); } System.out.println("main正在执行"+i); } } }
运行结果:
05线程状态观测
-
线程状态。线程可以处于以下状态之一:
-
NEW
尚未启动的线程处于此状态。 -
RUNNABLE
在Java虚拟机中执行的线程处于此状态。 -
BLOCKED
被阻塞等待监视器锁定的线程处于此状态。 -
WAITING
正在等待另一个线程执行特定动作的线程处于此状态。 -
TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 -
TERMINATED
已退出的线程处于此状态。
一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
-
public class ThreadState { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("线程正在执行"); }); //观察状态 //thread.getState()的返回值类型为Thread类中的State(Thread.State) Thread.State state = thread.getState(); System.out.println(state);//NEW //线程启动后 thread.start(); System.out.println(thread.getState());//RUNNABLE while(state!=Thread.State.TERMINATED){ Thread.sleep(200);//主线程休眠200ms state=thread.getState();//state更新 System.out.println(state); } //thread.start();//出错,因为线程死亡后,不能再次启动(即线程只能启动一次) } }
运行结果:
07线程优先级
-
线程优先级用数字表示,范围1~10
-
Thread.MAX_PRIORITY=10
-
Thread.NORM_PRIORITY=5
-
Thread.MIN_PRIORITY=1
-
-
优先级越高,越可能被CPU调用
-
获得优先级的方法:getPriority()
-
改变优先级的方法:setPriority(int xxx)
public class ThreadPriority { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); Runnable myPrority = new MyPrority(); Thread t1 = new Thread(myPrority,"t1"); Thread t2 = new Thread(myPrority,"t2"); Thread t3 = new Thread(myPrority,"t3"); Thread t4 = new Thread(myPrority,"t4"); Thread t5 = new Thread(myPrority,"t5"); Thread t6 = new Thread(myPrority,"t6"); t1.start();//5 t2.setPriority(Thread.MIN_PRIORITY);//1 t2.start(); t3.setPriority(3); t3.start(); t4.setPriority(Thread.NORM_PRIORITY);//5 t4.start(); t5.setPriority(Thread.MAX_PRIORITY);//10 t5.start(); //t6.setPriority(11);//越界 //t6.setPriority(0);//越界 t6.start(); } } class MyPrority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); } }
08守护线程
-
线程分为用户线程和守护线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕
-
守护线程:记录操作日志,监控内存,垃圾回收
//测试守护线程 //上帝守护者人们 public class DaemonThread { public static void main(String[] args) { God god = new God(); People people = new People(); //设置守护线程 Thread thread=new Thread(god); thread.setDaemon(true);//默认false表示用户线程,true为守护线程 thread.start(); new Thread(new People()).start(); } } //God线程 class God implements Runnable{ @Override public void run() { while(true){ System.out.println("上帝守护人们");} } } //People线程 class People implements Runnable{ @Override public void run() { for (int i = 1; i <= 120; i++) { System.out.println("第"+i+"年,人们开心的活着"); } System.out.println("=====Goodbye World!====="); } }
08线程同步
多个线程操作同一个资源
队列+锁保证线程同步
锁机制 synchronized
01线程不安全案例
不安全的买票:
public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"黄牛A").start(); new Thread(buyTicket,"黄牛B").start(); new Thread(buyTicket,"黄牛C").start(); new Thread(buyTicket,"观众").start(); } } class BuyTicket implements Runnable{ //票数 static int ticketNums=10; //标志位,用于停止线程 boolean flag=true; @Override public void run() { while(flag){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } buy(); } } public void buy(){ if (ticketNums<=0){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNums--)+"张票"); } }
不安全的取钱:
//模拟,两个人取同一账户里的钱 public class UnsafeBank { public static void main(String[] args) { //一个账户 Account account=new Account(100,"结婚基金"); //两个人取同一个账户里的钱 Withdraw man=new Withdraw(account,100,"男方"); Withdraw woman=new Withdraw(account,50,"女方"); man.start(); woman.start(); } } //账户 class Account{ int money;//余额 String name;//账户名 public Account(int money, String name) { this.money = money; this.name = name; } } //银行:模拟取钱操作 class Withdraw extends Thread{ Account account;//账户 int withdrawMoney;//要取的钱 int nowMoney;//取到人手里的钱 public Withdraw(Account account,int withdrawMoney,String name){ //name:线程名 super(name); this.account=account; this.withdrawMoney=withdrawMoney; } //取钱 @Override public void run() { if(account.money-withdrawMoney<0) { System.out.println("账户余额不足,取钱失败"); return; } //用sleep放大多线程可能出现的问题 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } account.money-=withdrawMoney; nowMoney+=withdrawMoney; //这里的this就是Thread.currentThread() System.out.println(this.getName()+"取完"+account.name+"账户里的钱后,现在手里的钱为"+nowMoney); System.out.println(account.name+"的账户余额为"+account.money); } }
不安全的集合:
import java.util.ArrayList; import java.util.List; //(这个集合的例子举的不好) public class UnsafeList { public static void main(String[] args) throws InterruptedException { List<String> list=new ArrayList<String>(); for (int i = 0; i < 100; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(200); sleep是为了让主线程的System.out.println(list.size())在其他线程都运行完再输出(这个集合的例子举的不好) System.out.println(list.size()); //打印出来不一定是100,可能小于00,因为多个线程并发时,可能同时执行list.add(),将两个线程添加到同一内存空间 } }
02同步方法
-
每个对象对应一把锁
-
线程若想调用synchronized方法/块,必须获得synchronized所修饰对象的锁,否则线程阻塞;synchronized方法/块一旦执行就独占该锁,直到执行完才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
synchronized的三种应用方式:
synchronized关键字最主要有以下3种应用方式,下面分别介绍
-
修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
-
修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
-
修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
我们以方法举例可以有如下的几种情况:
-
修饰实例方法, 这里默认的锁就是当前
类的实例对象
public synchronized void t0(){ // 方法体 }
-
修饰静态方法 , 这里默认的锁就是当前
类的class对象
public synchronized static void t0(){ // 方法体 }
-
修饰代码块
-
锁一个对象
public void t2() { synchronized (o) { // 方法体 } }
-
锁一个对象的class
public void t3() { synchronized (o.getClass()) { // 方法体 } }
-
总结:
有两种锁,对象锁和Class锁。
Class锁允许所有的Class相同的对象都拿到资源,
对象锁就单纯的只有这个对象才能获取到锁。
静态都是锁类的 class。其他的时候我们都是习惯于单纯的锁对象。
synchronized用法
-
synchronized方法:用synchronized修饰方法
eg:public synchronized void method(){}
-
synchronized块:synchronized(Obj){}
Obj通常是共享资源
不安全的买票:锁 buyTicket
public synchronized void buy(){ if (ticketNums<=0){ flag=false; return; }
不安全的银行:锁 account
synchronized (account){ if(account.money-withdrawMoney<0) { System.out.println("账户余额不足,取钱失败"); return; } //用sleep放大多线程可能出现的问题 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } account.money-=withdrawMoney; nowMoney+=withdrawMoney; //这里的this就是Thread.currentThread() System.out.println(this.getName()+"取完"+account.name+"账户里的钱后,现在手里的钱为"+nowMoney); System.out.println(account.name+"的账户余额为"+account.money); }
不安全的集合:锁 list
synchronized (list){ list.add(Thread.currentThread().getName()); }
09死锁
死锁产生的四个必要条件(缺一不可)
-
互斥条件
-
请求与保持条件
-
不剥夺条件
-
循环等待条件
以下程序会死锁:
//死锁:多个线程互相持有对方需要的资源不释放,然后形成僵持 public class DeadLock { public static void main(String[] args) { MakeUp girl1=new MakeUp(0,"小光"); MakeUp girl2=new MakeUp(1,"小雪"); 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;//选择 规定0:先拿口红再拿镜子 1;先拿镜子再拿口红 String girlName;//使用化妆品的人 MakeUp(int choice, String girlName){ this.choice=choice; this.girlName=girlName; } @Override public void run() { try { makeUp();//化妆 } catch (InterruptedException e) { e.printStackTrace(); } } //化妆,互相持有对方的锁,就是需要拿到对方的资源 private void makeUp() throws InterruptedException { if(choice==0){ synchronized (lipstick){ System.out.println(this.girlName+"获得口红的锁"); Thread.sleep(1000); synchronized (mirror){ System.out.println(this.girlName+"获得镜子的锁"); } } }else if(choice==1){ synchronized (mirror){ System.out.println(this.girlName+"获得镜子的锁"); Thread.sleep(1000); synchronized (lipstick){ System.out.println(this.girlName+"获得口红的锁"); } } } } }
上例:在synchronized块中还有synchronized块
解决方法:将synchronized块中的synchronized块拿出来
if(choice==0){ synchronized (lipstick){ System.out.println(this.girlName+"获得口红的锁"); Thread.sleep(1000); } synchronized (mirror){ System.out.println(this.girlName+"获得镜子的锁"); } }else if(choice==1){ synchronized (mirror){ System.out.println(this.girlName+"获得镜子的锁"); Thread.sleep(1000); } synchronized (lipstick){ System.out.println(this.girlName+"获得口红的锁"); } }
10Lock锁
-
lock是显示锁(手动开关锁,别忘记关闭锁) synchronized是隐式锁,出了作用域自动释放
-
Lock只有代码块锁,synchronized有代码块锁和方法锁
-
使用Lock锁,JVM将花费较少的时间来调度线程
import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) { TestLock2 testLock2=new TestLock2(); new Thread(testLock2).start(); new Thread(testLock2).start(); new Thread(testLock2).start(); } } class TestLock2 implements Runnable{ int ticketNums=10; //定义lock锁 private final ReentrantLock lock=new ReentrantLock(); @Override public void run() { while(true){ try{ lock.lock();//加锁 if (ticketNums>0){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNums--); } else{ break; } } finally { lock.unlock();//解锁 } } } }
11线程协作
生产者消费者问题
wait()与notify()
wait()方法:是让当前线程等待的,即让线程释放了对共享对象的锁,不再继续向下执行。
wait(long timeout)方法:可以指定一个超时时间,过了这个时间如果没有被notify()唤醒,则函数还是会返回。如果传递一个负数timeout会抛出IllegalArgumentException异常。
notify()方法:会让调用了wait()系列方法的一个线程释放锁,并通知其它正在等待(调用了wait()方法)的线程得到锁。
notifyAll()方法会唤醒所有在共享变量上由于调用wait系列方法而被挂起的线程。
注意:
调用wait()、notify()方法时,当前线程必须要成功获得锁(必须写在同步代码块锁中),否则将抛出异常。
01管程法
//测试生产者消费者问题 //1.管程法:利用缓冲区解决 public class TestPC { public static void main(String[] args) { SynContainer container=new SynContainer(); new Productor(container).start(); new Consumer(container).start(); } } //生产者 class Productor extends Thread{ SynContainer container; public Productor(SynContainer container){ this.container=container; } //生产 @Override public void run() { for (int i = 1; i <= 10; i++) { container.push(new Chicken(i)); System.out.println("生产了第"+i+"只鸡"); } } } //消费者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container=container; } //消费 @Override public void run() { for (int i = 1; i <= 10; i++) { System.out.println("消费了第"+container.pop().id+"只鸡"); } } } //产品 class Chicken{ int id;//产品编号 public Chicken(int id) { this.id = id; } } //缓冲区 class SynContainer{ //容器大小 Chicken[] chickens=new Chicken[10]; //容器计数器 int count=0; //生产者放入产品 public synchronized void push(Chicken chicken){ //若容器满,等待消费 if(count==chickens.length){ //通知消费者消费,生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //若容器没满,向容器丢入产品 chickens[count++]=chicken; //通知消费者消费 this.notify(); } //消费者消费产品 public synchronized Chicken pop(){ //判断能否消费 //若不能消费 if(count==0){ //等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //若可以消费 count--; Chicken chicken=chickens[count]; this.notify(); return chicken; } }
02信号灯法
//测试生产者消费者问题 //2信号灯法,利用标志位解决 public class TestPC2 { public static void main(String[] args) { Dishes dish=new Dishes(); new Cooker(dish).start(); new Customer(dish).start(); } } //生产者-->厨师 class Cooker extends Thread{ Dishes dish; public Cooker(Dishes dish){ this.dish=dish; } @Override public void run() { for (int i = 0; i < 3; i++) { this.dish.cook("好吃的菜"+(i+1)); } } } //消费者-->顾客 class Customer extends Thread{ Dishes dish; public Customer(Dishes dish){ this.dish=dish; } @Override public void run() { for (int i = 0; i < 3; i++) { this.dish.eat(); } } } //产品-->菜品 class Dishes{ //厨师做菜,顾客等待 T //顾客吃菜,厨师等待 F String dish;//表演的节目 boolean flag=true; //做菜 public synchronized void cook(String dish){ if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("厨师做了:"+dish); //通知顾客吃菜 this.notifyAll(); this.dish=dish; this.flag=!this.flag; } //吃菜 public synchronized void eat(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("顾客吃了:"+dish); //通知厨师做菜 this.notifyAll(); this.flag=!this.flag; } }
12线程池
背景:线程经常创建和销毁,会使用特别大的资源
思路:提前创建多个线程,放入线程池中,使用时直接获取,使用完放回池 中。可以避免频繁创建销毁线程,实现重复利用。
好处:
-
提高响应速度(减少了创建新线程的时间)
-
降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
-
便于线程管理
-
corePoolSize:核心池的大小
-
maximumPoolSize:最大线程数
-
keepAliveTime:线程没有任务时最多保持多长时间后会终止
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;//测试线程池
public class TestPool {
public static void main(String[] args) {
//1.创建服务,创建线程池
//newFixedThreadPool()中参数为线程池大小
ExecutorService service= Executors.newFixedThreadPool(4);//2.执行run()
service.execute(new MyThread2());
service.execute(new MyThread2());
service.execute(new MyThread2());
service.execute(new MyThread2());//3.关闭连接
service.shutdown();
}
}class MyThread2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
-