多线程详解---(多案例实战)

多线程

1、区分单线程和多线程

  • 单线程:就像是做饭,洗衣服,煮水,一个一个进行
  • 多线程:在单线程的基础上,可以考虑煮水的时候,洗衣服节约时间

在这里插入图片描述

package com.kong.thread;

//创建线程,重写run方法,start方法开启线程
public class thread1 extends Thread {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i <1000 ; i++) {
            System.out.println("你好");
        }
    }

    public static void main(String[] args) {

        thread1 thread1=new thread1();//创建线程
        thread1.start();//start开启多线程
//        thread1.run();//如果是run方法,只是将run方法运行,并不是开启多线程

        for (int i = 0; i <1000 ; i++) {
            System.out.println(i);
        }
    }
}

测试结果:如果是run方法,就是按照你好输出完毕再输出i,如果是start(多线程)方法,则run方法跟i交替输出

2、网图下载

  • 首先我们要知道的是多线程的调度,是CPU在操作的,而代码执行过程中,下载的网图是先后顺序的,但是如果跟第一点写的煮水洗衣服,是不是煮水会先好,多线程也是如此,就是一个争取CPU调度的过程
  • 我们编写一段代码来试着探讨一下吧
package com.kong.thread;

import org.apache.commons.io.FileUtils;

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

//1.下载图片,需要一个下载的方法
//2.编写构造器
//3.new一个下载方法
//4.编写main方法下载图片
public class thread2 extends Thread {

    private String url;
    private String name;

    public thread2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        DownPicture downPicture=new DownPicture();
        downPicture.down(url,name);
        System.out.println(name+"下载完毕");
    }

    public static void main(String[] args) {
        thread2 t1=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过1");
        thread2 t2=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过2");
        thread2 t3=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过3");

        //开启多线程
        t1.start();
        t2.start();
        t3.start();
    }

}

//图片下载方法
class DownPicture{
    public void down(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 运行结果不难发现,三张相同的图片运行的顺序不一样,这是因为多线程的CPU调度,每个线程都在争取运行,导致相差不多的运行时间可以变化输出

3、Runable接口

启动线程方式:传入目标对象+Thread对象.start

package com.kong.thread;

public class runable implements Runnable {
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        runable runable=new runable();//创建线程
        new Thread(runable).start();//开启线程

        for (int i = 0; i < 1000; i++) {
            System.out.println("ni");
        }
    }
}

在Thread类里面,继承了runable接口

4、并发问题

package com.kong.thread;

//模拟购票
public class runable2 implements Runnable {

    //定义一些票数
    private int tickNum=10;

    public void run() {
        while(true){
            if(tickNum<=1){
                break;
            }
            //模拟购票操作所需时间
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到第"+tickNum--+"票");
        }
    }

    public static void main(String[] args) {
        runable2 runable2=new runable2();

        new Thread(runable2,"小红").start();
        new Thread(runable2,"小明").start();
        new Thread(runable2,"小花").start();
    }
}

注意:在模拟购票所需时间之后会出现一种一起同时购买同一张票的情况(主要原因是你还在买票时间,有人也在买这张票)

5、龟兔赛跑问题

package com.kong.thread;

public class race implements Runnable {

    private String winner=null;

    public void run() {

    for (int i = 0; i <=100; i++) {
        //模拟兔子睡觉
                     if(Thread.currentThread().getName()=="兔子"&&i%10==0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            boolean b = gameOver(i);
            if(b){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"米");
        }
    }
    private boolean gameOver(int foot){
        if (winner!=null) {
            return true;
        }else if(foot>=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();
    }
}

6、静态代理模式

package com.kong.thread;

public class staticProxy {

    public static void main(String[] args) {
        weddingCompany wedding=new weddingCompany(new you());
        wedding.HappyMarry();
    }
}

interface Marry{
    void HappyMarry();
}

//你去实现一个结婚的方法,此处的你为真实角色
class you implements Marry{
    public void HappyMarry() {
        System.out.println("你要结婚了");
    }
}

//结婚公司是作为代理角色
class weddingCompany implements Marry{

    private Marry target;

    public weddingCompany(Marry target){
        this.target=target;
    }
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    private void before(){
        System.out.println("婚前准备");
    }

    private void after(){
        System.out.println("婚后送客");
    }
}

7、Lambda表达式

函数式接口的定义:

  • 任何接口,如果只包含一个抽象方法,就称为函数式接口
  • 对于函数式接口,我们可以通过lambda表达式创建该接口对象
package com.kong.thread;

public class lambda{
    //静态内部类
//    static class Like implements ILike{
//        public void lambda() {
//            System.out.println("你好啊");
//        }
//    }

    public static void main(String[] args) {

        //局部内部类
//        class Like implements ILike{
//            public void lambda() {
//                System.out.println("你好啊");
//            }
//        }
//         ILike like=new Like();
//         like.lambda();

        //匿名内部类,只能借助父类或者接口
//        ILike like = new ILike() {
//            public void lambda() {
//                System.out.println("你好啊");
//            }
//        };
//         like.lambda();

        //lambda简化
        ILike like=()->{
            System.out.println("你好啊");
        };
        like.lambda();
    }
}

//定义一个函数接口
interface ILike{
    void lambda();
}

//实现类
//class Like implements ILike{
//    public void lambda() {
//        System.out.println("你好啊");
//    }
//}

总结

  1. 就是一个继承接口之后的简化
  2. 只适用于函数式接口

8、线程状态

  • 创建状态:new一个对象,线程对象一旦创建就进入新生状态
  • 就绪状态:当用start()方法式,线程立即进入就绪状态,但不一定马上调度
  • 阻塞状态:调用sleep,wait或者同步锁定,线程就会进入阻塞章台,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu的调度
  • 执行状态:此处才是线程真正执行线程体的代码块
  • 死亡状态:线程中断或者结束,都会让线程进入死亡状态,并且不可再重新启动

在这里插入图片描述

8.1、线程停止

  • 建议线程正常停止—>利用次数,不建议死循环
  • 建议使用标志位
  • 不建议使用stop或者destroy
package com.kong.thread;

public class threadStop implements Runnable {

    //设置一个标识位
    private boolean flag=true;

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

    public void stop(){
        this.flag=false;
    }

    public static void main(String[] args) {
        threadStop threadStop=new threadStop();
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
            if(i==90){
                threadStop.stop();
                System.out.println("此线程停止");
            }
        }
    }
}

8.2、线程休眠

  • sleep(时间)指定当前线程阻塞的毫秒数
  • sleep存在异常InterruptedException
  • sleep时间到达后进程回进入就绪状态
  • sleep可以模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁
package com.kong.thread;

import java.text.SimpleDateFormat;
import java.util.Date;

public class timeSleep {

    public static void main(String[] args) {
        tenDown();
    }
    public static void tenDown() {
//        //倒计时
//        int num = 10;
//        while (true) {
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(num--);
//            if (num <= 0) {
//                break;
//            }
//        }
//    }
        //打印系统当前的事件
        Date date = new Date(System.currentTimeMillis());//获取当前系统时间
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
            date = new Date(System.currentTimeMillis());
        }
    }

}

作用:放大事件可能发生的概率

8.3、线程礼让

  • 礼让线程,让当前正在执行的线程暂停,但是不阻塞
  • 运行转为就绪
  • cpu重新调度
package com.kong.thread;

public class threadYeid {
    public static void main(String[] args) {
        Myyied myyied = new Myyied();
        new Thread(myyied,"a").start();
        new Thread(myyied,"b").start();

    }
}
 class Myyied implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程停止");
    }
}

结论:礼让不一定能成功

8.4、线程强制执行join(插队)

package com.kong.thread;

public class threadjoin implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(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 <50 ; i++) {
            if(i==20){
                thread.join();
            }
            System.out.println("停止");
        }
    }
}

8.5、线程状态观察

package com.kong.thread;

public class state {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("ddd");
        });

        //观察状态
        Thread.State state=thread.getState();
        System.out.println(state);

        //启动后观察
        thread.start();
        state=thread.getState();
        System.out.println(state);

        while(state!=Thread.State.TERMINATED){
            Thread.sleep(100);
            state=thread.getState();//更新线程状态
            System.out.println(state);
        }
    }
}

8.6、线程优先级

  • 范围:1~10
  • 使用下列方法获取优先级
    • getPriority setPriority
  • 注意一点,一定要先设置优先级再启动线程

8.7、守护线程

  • 线程分为用户线程守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不需要等到守护线程执行完毕
package com.kong.thread;

import java.lang.management.ThreadMXBean;

//妈妈守护孩子,两个角色
public class daemon {
    public static void main(String[] args) {
        mother mother=new mother();
        son son=new son();
        Thread thread=new Thread(mother);
        thread.setDaemon(true);//默认是false,是用户进程
        thread.start();//守护线程开启
        new Thread(son).start();
    }
}

//妈妈
class mother implements Runnable{

    @Override
    public void run() {
        while(true){
            System.out.println("守护");
        }
    }
}

//儿子
class son implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("被守护");
        }
    }
}

9、线程同步机制(三大不安全案例)

形成的条件:队列+锁

就像是排队上厕所,排队是队列,锁是门,只有这样才能保证线程的安全

  • 买票(存在多个人同时购买一张票的情况)
package com.kong.thread;

//模拟购票
public class runable2 implements Runnable {

    //定义一些票数
    private int tickNum=10;

    public void run() {
        while(true){
            if(tickNum<=1){
                break;
            }
            //模拟购票操作所需时间
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到第"+tickNum--+"票");
        }
    }

    public static void main(String[] args) {
        runable2 runable2=new runable2();

        new Thread(runable2,"小红").start();
        new Thread(runable2,"小明").start();
        new Thread(runable2,"小花").start();
    }
}
  • 银行取钱(两人同时把钱取出,造成的不安全取款)
package com.kong.thread;

//模拟两人去银行取钱
public class marry {
    public static void main(String[] args) {
       //账户
        Account account=new Account(100,"旅游基金");

        bink kongkong=new bink(account,50,"小明");
        bink yuanyuan=new bink(account,100,"小红");

        kongkong.start();
        yuanyuan.start();

    }
}

//账户信息
class Account{
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

//模拟银行
class bink extends Thread{

    Account account;
    int raceMoney;//取出的钱
    int nowMoney;//现在的钱

    public bink(Account account, int raceMoney, String name) {
        super(name);
        this.account = account;
        this.raceMoney = raceMoney;
    }

    @Override
    public void run() {
        //取钱操作

        try {
            Thread.sleep(1000);//模拟取钱时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(account.money-raceMoney<0){
            System.out.println(Thread.currentThread().getName()+"钱不够取了");
            return;
        }
        account.money=account.money-raceMoney;//账户的余额
        nowMoney=nowMoney+raceMoney;//当前获得到的钱数

        System.out.println(account.name+"剩下"+account.money);
        System.out.println(Thread.currentThread().getName()+"拿到了"+nowMoney);
    }
}
  • 不安全的线程集合(存在同一个空间存放两个)
package com.kong.thread;

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

public class threadIO {
    public static void main(String[] args) throws InterruptedException {
        List<String> list=new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->
            {
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(300);
        System.out.println(list.size());
    }
}

10、同步方法和同步块

  1. 同步方法

    • 我们通过加synchronized关键字修饰即可将方法变为同步方法
    • 相对于队列加锁
    • 弊端:方法里面需要修饰的内容需要锁,但是锁的太多,浪费资源
  2. 同步块

    • synchronized(Obj){}
    • Obj称为同步监视器
      • Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
      • 同步方法中无需指定同步监视器,同步方法的监视器就是this,就是这个对象本身,或者class
    • 同步监视器的执行过程
      • 第一个线程访问,锁定同步监视器,执行其中代码
      • 第二个线程访问,发现同步监视器被锁定,无法访问
      • 第一个线程访问完毕,解锁同步监视器
      • 第二个线程访问,发现同步监视器没有锁,任何锁定并访问
  3. 修改购票为同步方法

public synchronized void run() {
    while(true){
        if(tickNum<=0){
            break;
        }
        //模拟购票操作所需时间
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到第"+tickNum--+"票");
    }
}
  1. 修改结婚基金

因为锁的是this,本质来说就是总存款像厕所,我们要把厕所锁起来,而排队跟线程就是如何利用这个锁(厕所)

@Override
public void run() {
    //取钱操作
    synchronized (account) {
        if(account.money-raceMoney<0){
            System.out.println(Thread.currentThread().getName()+"钱不够取了");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money=account.money-raceMoney;//账户的余额
        nowMoney=nowMoney+raceMoney;//当前获得到的钱数

        System.out.println(this.getName()+"拿到了"+nowMoney);
        System.out.println(account.name+"剩下"+account.money);
    }
}
  1. 多线程集合方式
List<String> list=new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
    new Thread(()->
    {
        synchronized (list){
            list.add(Thread.currentThread().getName());//锁住的是list对象
        }
    }).start();
}

集合的安全方法CopyOnWriteArrayList

package com.kong.thread;

import java.util.concurrent.CopyOnWriteArrayList;

public class threadsyn {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->
            {
   list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(300);
        System.out.println(list.size());
    }
}

11、死锁

死锁原因:多个线程各自占有一些共享资源,并且要等待占有资源运行完毕,才能让下一个线程占有;而导致两个或者两个以上同时占有同一个资源情况,称为死锁

package com.kong.thread;

public class deadLock{
    public static void main(String[] args) {
        people kongkong=new people(0,"kongkong");
        people yuanyuan = new people(1, "yuanyuan");

        kongkong.start();
        yuanyuan.start();
    }
}
//食物
class food{

}
//饮水
class drink{

}

class people extends Thread {
    static food f = new food();
    static drink d = new drink();

    int choice;//选择
    String name;

    people(int choice, String name) {
        this.choice = choice;
        this.name = name;
    }

    @Override
    public void run() {
        try {
            person();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void person() throws InterruptedException {
        if (choice == 0) {
            synchronized (f) {
                System.out.println(this.name + "获得食物");
                Thread.sleep(1000);
            }
            synchronized (d) {
                System.out.println(this.name + "获得饮水");

            }
        } else {
            synchronized (d) {
                System.out.println(this.name + "获得食物");
                Thread.sleep(2000);
                }
            synchronized (f) {
                System.out.println(this.name + "获得饮水");

            }
        }
    }
}

当两件事情同时放在同一个同步方法的时候,就会产生死锁,解决办法就是将事情放出来,让另一个线程拿到。

死锁产生条件

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求和保持条件:一个进程因请求资源而阻塞时,对以获得的资源保持不放
  3. 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

12、Lock锁

Lock锁synchronized对比

  • Lock是显示锁(手动开启和关闭),synchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁,synchronized有代码块和方法锁
  • Lock锁,Jvm将花费较少的事件来调度线程,性能更好,并且有更好的扩展性
  • 优先级:Lock>同步代码块>同步代码方法
package com.kong.thread;

import java.util.concurrent.locks.ReentrantLock;

//模拟购票
class runable2 implements Runnable {

    //定义一些票数
    private int tickNum=100;
    //定义lock锁
    private final ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try{
                lock.lock();
                if(tickNum>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"拿到第"+tickNum--+"票");
                }else {
                    break;
                }
            }finally {
                //解锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        runable2 runable2=new runable2();

        new Thread(runable2,"小红").start();
        new Thread(runable2,"小明").start();
        new Thread(runable2,"小花").start();
    }
}

13、线程协作

角色:生产者,消费者

背景:生产者生产东西,消费者拿东西,消费者拿东西的时候,生产者还没生产好,这时候我们就提出一个疑问,能不能让消费者知道生产者做完了,或者生产者知道消费者需要来拿东西了?

解决方案

  1. 管程法:在生产者和消费者之间新建一个缓冲区,这样就可以把东西储存到缓冲区,消费者看到就可以直接取,取不到,生产者马上生产

在这里插入图片描述

  1. 信号灯法:我们可以在生产者或者消费者设置一个true,当为true时,不给予通过,等待判断生产者有东西让消费者拿的时候,再将其放出

在这里插入图片描述

13.1、管程法

package com.kong.thread;

public class testPC {
    public static void main(String[] args) {
        syn container=new syn();

        new Product(container).start();
        new Consumer(container).start();
    }
}

//生产者
class Product extends Thread{
    syn container;

    public Product(syn container){
        this.container=container;
    }
    //生产
    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了"+i+"只鸡");
            container.push(new Chicken(i));//生产鸡
        }
    }
}
//消费者
class Consumer extends Thread{
    syn container;

    public Consumer(syn container){
        this.container=container;
    }
    //消费
    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了第"+container.pop().id+"只鸡");
        }
    }
}

//产品
class Chicken{
    int id;
    public Chicken(int id){
        this.id=id;
    }
}

//缓冲区
class syn{
    //需要一个容器大小
    Chicken[] chickens=new Chicken[10];
    //容器计数器
    int count=0;
    //生产者放入产品
    public synchronized void push(Chicken chicken){
        //如果容器满了,就需要等待消费者消费
        while (count==10){
            //通知消费者消费,生产等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        //如果没有满,需要丢入产品
        chickens[count] = chicken;
        count++;
        //通知消费者消费
        this.notifyAll();
    }
    //消费者消费产品
    public synchronized Chicken pop(){
        //判断是否消费
        if(count==0){
            //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken=chickens[count];

        //吃完通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

13.2、信号灯法

package com.kong.thread;

public class testPC2 {
    public static void main(String[] args) {
        TV tv=new TV();
        new Player(tv).start();
        new Watch(tv).start();
    }
}

//演员
class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0){
                this.tv.play("金鹰卫视");
            }else {
                this.tv.play("儿童频道");
            }
        }
    }
}
//观众
class Watch extends Thread{
    TV tv;
    public Watch(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

//节目
class TV{
    String voice;
    boolean flag=true;

    //表演
    public synchronized void play(String voice) {
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了" + voice);
        //通知观众观看
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }

    //观看
    public synchronized void watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag=!this.flag;
    }

}

14、线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大

思路:提前创建好多个线程,放入线程池中,使用时直接获取,用完放回,避免频繁创建销毁,实现重复利用

优点

  • 提高响应速度
  • 减低资源消耗
  • 便于线程管理

使用

  • ExecutorService:真正的线程池接口
  • Executors:工具类、线程池的工厂类,用于创建返回的线程池
package com.kong.thread;

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

public class testPool {
    public static void main(String[] args) {
        //创建线程池
        //newFixedThreadPool线程池大小
        ExecutorService service= Executors.newFixedThreadPool(10);

        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //关闭连接
        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘凉者 栽树人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值