java多线程全面解析

java多线程

1、线程简介

普通方法和多线程:

image-20220928201802199

进程:在操作系统中运行的程序就是进程,比如你的QQ,播放器,游戏,IDE等等。

image-20220928202039421

程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。

进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位通常在一个进程中可以包含若干个线程,当然一

个进程中至少有一个线程,不然没有存在的意义。

线程是CPU调度和执行的的单位。

image-20220928202422688

tips:

1、线程就是独立的执行路径;

2、在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;

3、main()称之为主线程,为系统的入口,用于执行整个程序;

4、在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的

千预的。

5、对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间,并发控制开销。

6、每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

2、线程实现(三种)

继承Thread类(重点)

步骤:

1、自定义线程类继承Thread类重写run()方法

2、编写线程执行体创建线程对象

3、调用start()方法启动线程

示例代码:
package Multithread;

public class TestThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("线程1");
        }
    }

    public static void main(String[] args) {
//        两个线程同时执行
        new TestThread1().start();
        for (int i = 0; i < 200; i++) {
            System.out.println("主线程");
        }
    }
}
多线程下载图片:
package Multithread;

import org.apache.commons.io.FileUtils;

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

public class TestThread2 extends Thread {
    private String url;
    private String name;

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

    @Override
    public void run() {
        new Downloader().downloader(url,name);
        System.out.println("下载了图片:"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1=new TestThread2("https://img-home.csdnimg.cn/images/20220928102134.jpg","1.jpg");
        TestThread2 t2=new TestThread2("https://img-operation.csdnimg.cn/csdn/silkroad/img/1664246005001.jpg","2.jpg");
        TestThread2 t3=new TestThread2("https://img-operation.csdnimg.cn/csdn/silkroad/img/1663729624980.jpg","3.jpg");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Downloader{
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Downloader捕获到异常");
        }
    }
}

实现Runnable接口(重点)

步骤:

1、定义MyRunnable类实现Runnable接口

2、实现run()方法,编写线程执行体

3、创建线程对象,调用start()方法启动线程

基础代码:
package Multithread;

public class TestThread3 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("线程1");
        }
    }

    public static void main(String[] args) {
        Thread t=new Thread(new TestThread3());
        t.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("主线程");
        }
    }
}
体现Runnable的多继承性:
package Multithread;

public class TestThread4 implements Runnable{
    int ticket=100;
    @Override
    public void run() {
        while (ticket>0){
            System.out.println(Thread.currentThread().getName()+"抢到票:"+ticket--);
        }
    }

    public static void main(String[] args) {
        TestThread4 r=new TestThread4();
//        多继承使用
        new Thread(r,"小明").start();//小明作为线程名
        new Thread(r,"李华").start();
        new Thread(r,"黄牛").start();
    }
}
龟兔赛跑:
package Multithread;

public class TestRace implements Runnable{
    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i <=100; i++) {
//            判断比赛是否结束
            if (gameover(i)) {
                break;
            }
//            模拟兔子睡觉
            if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }
//    判断获胜者
    public Boolean gameover(int step){
        if (winner!=null)return true;
        else {
            if (step>=100){
                winner=Thread.currentThread().getName();
                System.out.println("获胜者是"+winner);
                return true;
            }
        }
        return false;
    }

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

实现callable接口(了解)

步骤:

1、实现Callable接口,需要返回值类型

2、重写call方法,需要抛出异常

3、创建目标对象

4、创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);

5、提交执行:Future result1 = ser.submit(t1);

6、获取结果:boolean r1 = result1.get()

7、关闭服务:ser.shutdownNow();

示例代码:
package Multithread;

import java.util.concurrent.*;

public class TestThread5 implements Callable<Boolean> {
    private String url;
    private String name;

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

    @Override
    public Boolean call() {
        new Downloader().downloader(url, name);
        System.out.println("下载了图片:" + name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestThread5 t1 = new TestThread5("https://img-home.csdnimg.cn/images/20220928102134.jpg", "1.jpg");
        TestThread5 t2 = new TestThread5("https://img-operation.csdnimg.cn/csdn/silkroad/img/1664246005001.jpg", "2.jpg");
        TestThread5 t3 = new TestThread5("https://img-operation.csdnimg.cn/csdn/silkroad/img/1663729624980.jpg", "3.jpg");
        //创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提交执行:Future<Boolean> result1 = ser.submit(t1);
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t2);
        Future<Boolean> r3 = ser.submit(t3);
        //获取结果:boolean r1 = result1.get()
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();
        //关闭服务:ser.shutdownNow();
        ser.shutdownNow();
    }
}

补充:静态代理模式

真实对象专注做自己的事情,代理对象做真实对象的附加业务。

代码:

package Multithread;
/*
* 静态代理模式
* */
//实际类和代理类需实现同一接口
public class StaticP {
    public static void main(String[] args) {
        You y=new You();
        wedCompany wd=new wedCompany(y);
        wd.happymarry();
    }
}
interface Marry{
    void happymarry();
}
//需求者
class You implements Marry{
    @Override
    public void happymarry() {
        System.out.println("你结婚了");
    }
}
//代理
class wedCompany implements Marry{
    private Marry target;

    public wedCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void happymarry() {
        before();
        target.happymarry();
        after();
    }
    public void before(){
        System.out.println("结婚前");
    }
    public void after(){
        System.out.println("结婚后");
    }
}
lambda表达式
package Multithread;

public class TestT {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("哈哈哈")).start();
    }
}

3、线程状态

(线程五大状态)图解:

1、精简:

image-20220929164327395

2、详细:
image-20220929164542713

线程方法:

image-20220929171337847
停止线程:

1、不推荐使用JDK提供的stop()、destroy()方法。【已废弃】

2、推荐线程自己停止下来

3、建议使用一个标志位进行终止变量当flag=false,则终止线程运行。

停止线程推荐方式代码:
package Multithread;
/*
* 推荐使用的线程停止方式,使用一个外部标志位
* */
public class StateT 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) {
        StateT stateT = new StateT();
        Thread thread = new Thread(stateT);
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main");
            if (i==90){
                stateT.stop();
                System.out.println("线程停止");
            }
        }
    }
}
线程休眠:(Thread.sleep(1000))

sleep(时间)指定当前线程阻塞的毫秒数;

sleep存在异常InterruptedException;

sleep时间达到后线程进入就绪状态;

sleep可以模拟网络延时,倒计时等。

每一个对象都有一个锁,sleep不会释放锁;

使用案例(倒计时、打印系统当前时间)
package Multithread;

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

public class SleepT {

    public static void Down() throws InterruptedException {
        int times=10;
        while (times>=0){
            Thread.sleep(1000);
            System.out.println("倒计时:"+times--);
        }
    }

    public static void main(String[] args) throws InterruptedException {
//        倒计时
        Down();
//        打印系统当前时间
        Date time=new Date(System.currentTimeMillis());//获取系统当前时间
        while (true){
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
            time=new Date(System.currentTimeMillis());//更新系统当前时间
        }
    }
}
线程礼让:(Thread.yield())

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

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

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

代码:

package Multithread;

public class ThreadYield {
    public static void main(String[] args) {
        mythraed mythraed = new mythraed();
        new Thread(mythraed,"a").start();
        new Thread(mythraed,"b").start();
    }
}
class mythraed implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"结束");
    }
}
线程强制执行:(thread.join())

Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

可以想象成插队

测试代码:

package Multithread;

public class Threadjoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("vip"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Threadjoin());
        thread.start();
        for (int i = 0; i < 200; i++) {
            if (i==50){
                thread.join();
            }
            System.out.println("主线程"+i);
        }
    }
}
线程状态:Thread.getState()
线程优先级:

Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。

线程的优先级用数字表示,范围从1~10.

Thread.MIN_PRIORITY = 1;

Thread.MAX_PRIORITY = 10;

Thread.NORM_PRIORITY = 5;(默认优先级)

使用以下方式改变或获取优先级

getPriority()

setPriority(int xxx)

测试代码:

package Multithread;

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

    public static void main(String[] args) {
        ThreadPri tp=new ThreadPri();
        Thread t1 = new Thread(tp,"t1");
        Thread t2 = new Thread(tp,"t2");
        Thread t3 = new Thread(tp,"t3");
        Thread t4 = new Thread(tp,"t4");
        t1.setPriority(10);
        t2.setPriority(5);
        t3.setPriority(3);
        t4.setPriority(1);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

守护线程

线程分为用户线程和守护线程

虚拟机必须确保用户线程执行完毕

虚拟机不用等待守护线程执行完毕

如后台记录操作日志,监控内存,垃圾回收等待…

thread.setDaemon(true)//设置线程为守护线程

4、线程同步

简介:

形成条件:队列加锁

并发:同一个对象被多个线程操作。

线程不安全案例:

package Multithread;

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

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

同步方法:

由于我们可以通过private 关键字来保证数据对象只能被方法访问﹐所以我们只需要针对方法提出一套机制,这套机制就是

synchronized关键字,它包括两种用法:synchronized方法和synchronized块.

image-20220930150344027

synchronized方法控制对“对象”的访问,每个对象对应一把锁

每个synchronized方法都必须获得调用该方法的对象的锁才能执行﹐否则线程会阻塞,方法一旦执行就独占该锁,直到该方

法返回才释放锁﹐后面被阻塞的线程才能获得这个锁﹐继续执行

image-20220930150444004

代码:

package Multithread;

public class TestThread4 implements Runnable{
    private int ticket=100;
    private Boolean flag=true;
    @Override
    public void run() {
        while (flag){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
          flag = buy();
        }
    }
    public synchronized Boolean buy(){
        if (ticket<1){
            return false;
        }
        System.out.println(Thread.currentThread().getName()+"抢到票:"+ticket);
        ticket--;
        return true;
    }
    public static void main(String[] args) {
        TestThread4 r=new TestThread4();
//        多继承使用
        new Thread(r,"小明").start();
        new Thread(r,"李华").start();
        new Thread(r,"黄牛").start();
    }
}

同步块

同步块:synchronized (Obj ){ }

Obj称之为同步监视器:

Obj可以是任何对象﹐但是推荐使用共享资源作为同步监视器。

同步方法中无需指定同步监视器﹐因为同步方法的同步监视器就是this ,就是这个对象本身,或者是class。

同步监视器的执行过程:

  1. 第一个线程访问﹐锁定同步监视器﹐执行其中代码。

2.第二个线程访问﹐发现同步监视器被锁定,无法访问。

3.第一个线程访问完毕,解锁同步监视器。

4.第二个线程访问,发现同步监视器没有锁﹐然后锁定并访问。

代码示例:
package Multithread;

public class TestThread4 implements Runnable{
    private int ticket=100;
    private Boolean flag=true;
    @Override
    public void run() {
        while (flag){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this){
                flag = buy();
            }

        }
    }
    public  Boolean buy(){
        if (ticket<1){
            return false;
        }
        System.out.println(Thread.currentThread().getName()+"抢到票:"+ticket);
        ticket--;
        return true;
    }
    public static void main(String[] args) {
        TestThread4 r=new TestThread4();
//        多继承使用
        new Thread(r,"小明").start();
        new Thread(r,"李华").start();
        new Thread(r,"黄牛").start();
    }
}

死锁问题:

多个线程各自占有一些共享资源﹐并且互相等待其他线程占有的资源才能运行﹐而导致两个或者多个线程都在等待对方释放资

源﹐都停止执行的情形.某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题。

产生死锁的四个必要条件:

1.互斥条件:一个资源每次只能被一个进程使用。

2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

Lock

从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。

同步锁使用Lock对象充当java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

基本格式:
image-20220930164411667
代码示例:
package Multithread;

import java.util.concurrent.locks.ReentrantLock;

public class Lock1 {
    public static void main(String[] args) {
        TestLock testLock = new TestLock();
        new Thread(testLock ).start();
        new Thread(testLock ).start();
        new Thread(testLock ).start();
    }
}
class TestLock 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();//解锁
            }
        }
    }
}

5、线程协作(生产消费模型)

image-20220930170201045

应用场景∶生产者和消费者问题

假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费.

如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止.

如果仓库中放有产品﹐则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止.

1、管程法

image-20220930170853456
参考代码:(引用)
package Multithread;

public class ProAndCon1 {
    private static int count = 0;

    private static final int buffCount = 10;

    private static String lock = "lock";


    class Producer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock) {
                    while (count == buffCount) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    count++;
                    System.out.println(Thread.currentThread().getName() + "-生产者生产,数量为:" + count);
                    lock.notifyAll();
                }
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (lock) {
                    while (count == 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName() + "-消费者消费,数量为:"+ count);
                    lock.notifyAll();
                }
            }
        }
    }

    public static void main(String[] args) {
        ProAndCon1 waitTest = new ProAndCon1();
        new Thread(waitTest.new Producer()).start();
        new Thread(waitTest.new Consumer()).start();
        new Thread(waitTest.new Producer()).start();
        new Thread(waitTest.new Consumer()).start();
        new Thread(waitTest.new Producer()).start();
        new Thread(waitTest.new Consumer()).start();

    }
}

运行结果:

Thread-0-生产者生产,数量为:1
Thread-3-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-4-生产者生产,数量为:2
Thread-5-消费者消费,数量为:1
Thread-1-消费者消费,数量为:0
Thread-4-生产者生产,数量为:1
Thread-5-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-1-消费者消费,数量为:0
Thread-0-生产者生产,数量为:1
Thread-3-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-1-消费者消费,数量为:0
Thread-4-生产者生产,数量为:1
Thread-0-生产者生产,数量为:2
Thread-5-消费者消费,数量为:1
Thread-3-消费者消费,数量为:0
Thread-4-生产者生产,数量为:1
Thread-0-生产者生产,数量为:2
Thread-5-消费者消费,数量为:1
Thread-3-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-1-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-4-生产者生产,数量为:2
Thread-1-消费者消费,数量为:1
Thread-5-消费者消费,数量为:0
Thread-0-生产者生产,数量为:1
Thread-3-消费者消费,数量为:0
Thread-4-生产者生产,数量为:1
Thread-1-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-3-消费者消费,数量为:0
Thread-0-生产者生产,数量为:1
Thread-5-消费者消费,数量为:0
Thread-2-生产者生产,数量为:1
Thread-5-消费者消费,数量为:0
Thread-4-生产者生产,数量为:1
Thread-0-生产者生产,数量为:2
Thread-1-消费者消费,数量为:1
Thread-3-消费者消费,数量为:0

2、信号灯法

实质是缓冲区为1的线程池

示例代码:
package Multithread;

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

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

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            if (i%2==0){
                this.tv.play("B站LOL直播中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                this.tv.play("抖音视频");
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//观众
class Watcher implements Runnable{
    TV tv;
    public Watcher(TV tv) {
        this.tv = tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            this.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.voice=voice;
        this.flag=!this.flag;
        this.notifyAll();//通知观众观看

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

运行结果:

演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中
演员表演了:抖音视频
观看了节目:抖音视频
演员表演了:B站LOL直播中
观看了节目:B站LOL直播中

3、线程池(浅析,重点见下一章)

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

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。

好处:
提高响应速度(减少了创建新线程的时间)

​ 降低资源消耗(重复利用线程池中线程,不需要每次都创建)

​ 便于线程管理(…)

​ corePoolSize:核心池的大小

​ maximumPoolSize:最大线程数

​ keepAliveTime:线程没有任务时最多保持多长时间后会终止

JDK 5.0起提供了线程池相关API: ExecutorService和Executors

ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

​ void execute(Runnable command)∶执行任务/命令,没有返回值,一般用来执行Runnable

​ Future submit(Callable task):执行任务,有返回值,一般又来执行Callable

​ void shutdown()∶关闭连接池

Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

分类:

FixedThreadPool:固定长度的线程池,可以控制线程的最大并发数,超出的线程会放到队列中。

SingleThreadExecutor:单线程线程池,它只会用唯一的线程来执行任务。

CachedThreadPool:可缓存的线程池,如果数据请求过多,它会不断创建新的线程,并且它还可以灵活回收空闲的线程。

ScheduledThreadPool:用于定时执行任务的线程池。

image-20221004164756853
示例代码:
package Multithread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args) {
        //    1、创建服务
        //    2、创建线程池
        ExecutorService service= Executors.newFixedThreadPool(10);//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() {
            System.out.println(Thread.currentThread().getName());
    }
}
:执行任务,有返回值,一般又来执行Callablevoid shutdown()∶关闭连接池

**Executors**:工具类、线程池的工厂类,用于创建并返回不同类型的线程池



#### 分类:

FixedThreadPool:固定长度的线程池,可以控制线程的最大并发数,超出的线程会放到队列中。

SingleThreadExecutor:单线程线程池,它只会用唯一的线程来执行任务。

CachedThreadPool:可缓存的线程池,如果数据请求过多,它会不断创建新的线程,并且它还可以灵活回收空闲的线程。

ScheduledThreadPool:用于定时执行任务的线程池。

<img src="https://i-blog.csdnimg.cn/blog_migrate/f78e1fd157c6957a366bea885fc08289.png" alt="image-20221004164756853" style="zoom: 50%;" />



#### 示例代码:

```java
package Multithread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args) {
        //    1、创建服务
        //    2、创建线程池
        ExecutorService service= Executors.newFixedThreadPool(10);//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() {
            System.out.println(Thread.currentThread().getName());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱打辅助的小可爱

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

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

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

打赏作者

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

抵扣说明:

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

余额充值