多线程

多线程

线程简介

​ 线程:目前正在做的事情,独立执行的路径

​ 多线程:目前有多个事情同时进行

​ 进程:操作系统运行的程序。eg:播放器、聊天工具…

​ 一个进程可以拥有多个 线程。 eg:视频同时播放音乐、图形…

线程创建

三种创建方式

	Thread (class)
    	=> class xx extends Thread
	Runnable (Interface)
		=> class xx implements Runnable
	Callable (Interface)
		=> class xx implements Callable
	

Thread

​ 开发步骤:

​ 1.自定义线程类继承Thread类

​ 2.重写run()方法,编写线程执行体

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

​ 注: 线程不一定立即执行、由 CPU 安排调度

​ 故可能会交替控制,因为同时只做一件事情

//1.
class MyThread extends Thread{
    //2.

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("这是run方法--"+i);
        }
    }
}

public class Test  {
    //main线程 主线程
    public static void main(String[] args) {

        //3.
        MyThread myThread = new MyThread();
        myThread.start();



        for (int i = 0; i < 400; i++) {
            System.out.println("这是main "+i);
        }

        /*
         中间部分会出现这种 情况
            这是run方法--8
            这是run方法--9
            这是main 120
            这是run方法--10
            这是main 121
            这是run方法--11
            这是main 122
            这是run方法--12
            这是main 123
            这是run方法--13
            这是main 124

            
         */
    }
}

Runnable

​ 【推荐该方法、因为Java是单继承】

​ 开发步骤:

​ 1.定义xxxx类实现Runnable接口

​ 2.实现run()类

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

​ 注:

​ 相对于Thread 方式、Runnable需要 new 一个Thread类进行代理

//1.
class MyRunnable implements Runnable{
    //2.

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("这是Runnable-run方法--"+i);
        }
    }
}

public class Test  {
    //main线程 主线程
    public static void main(String[] args) {

        //3.
        MyRunnable myRunnable = new MyRunnable();

        //创建线程对象,通过线程对象来开启线程 ->代理
        new Thread(myRunnable).start();
    }
}

Callable

​ 【了解即可】

​ 开发步骤:

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

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

​ 3.创建目标对象

​ 4.创建执行服务

​ 5.提交执行

​ 6.获取结果

​ 7.关闭服务

案例:龟兔赛跑

class Race implements Runnable{

    //胜利方
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {

            //设置某一对象 休眠
            if (Thread.currentThread().getName().equals("兔子") && i%10 == 0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //作为结束的条件
            boolean flag = gameOver(i);
            if (flag) break;

            System.out.println(Thread.currentThread().getName()+"==>跑了 "+i +" 步");
        }
    }

    //判断谁是胜利方
    private boolean gameOver(int step){
        if (winner != null){
            return true;
        }
        if (step >= 100){
            winner = Thread.currentThread().getName();
            System.out.println("winner is " + winner);
            return true;
        }
        return false;

    }
}

public class Test  {
    public static void main(String[] args) {
        Race race =new Race();

        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}



Lambda 表达式

​ 避免 匿名内部类 定义 过多

​ 增加可读性

​ 保留核心逻辑

​ 实质:函数式编程

(params)->expression[表达式]
(params)->statement[语句]
(params)->{statements}

函数式接口

​ 只包含唯一一个抽象方法

public interface xxx{
	public abstract void xxx();
}

​ 对于此类,我们可以通过lambda表达式 来创建该接口对象

举例

原始版本
//1.定义函数式接口
interface MyLambda{
    void run();
}



public class Test  {



    public static void main(String[] args) {
        //2.创建对象
        MyLambda lambda;

        //3.实现匿名内部类 Lambda 表达式
        lambda = () ->{
            System.out.println("Lambda 表达式");
        };

        lambda.run();


    }
}
简化一

如果 抽象方法有参数,还可以将 形参类型 省略掉

//1.定义函数式接口
interface MyLambda{
    void run(int nums);
}



public class Test  {
    public static void main(String[] args) {
        //2.创建对象
        MyLambda lambda;

        //3.实现内部类 Lambda 表达式
//        lambda = (int nums) ->{
//            System.out.println("我跑了 "+nums + "公里");
//        };
        lambda = (nums) ->{
            System.out.println("我跑了"+nums + " 公里");
        };

        lambda.run(10); //我跑了10 公里
    }
}

简化二

​ 简化括号 + 简化 花括号

​ 注:

​ 只有单个(一个参数、一行代码)的情况式才能简化掉、否则必须使用。

​ 必须是函数式接口( 类型为接口、 且仅有一个抽象方法 )

public static void main(String[] args) {
        MyLambda lambda;

        lambda = nums -> System.out.println("我跑了 "+nums + " 公里");;

        lambda.run(12); //我跑了 12 公里
 }

线程状态

1.创建状态
	--->就绪状态 【启动线程】
2.就绪状态
	--->运行状态 【获取CPU资源】
3.阻塞状态
	--->就绪状态 【阻塞解除】
4.运行状态
	--->阻塞状态 【等待用户输入线程休眠等】
	--->就绪状态 【释放CPU资源】
	--->死亡状态  【线程自然执行完毕 || 外部干涉终止线程】
5.死亡状态

线程方法

方法说明
setPriority(int newPriority)更改线程优先级
static void sleep(long millis)在指定的毫秒数内让当前线程休眠
void join()等待该线程终止
static void yield()暂定当前线程对象,并执行其他线程
void interrupt()中断该线程
boolean isAlive判断线程是否处于活动状态

停止线程

​ 不推荐jdk使用的stop()、destroy()

​ 推荐线程自己停下来

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

//1.线程正常停止 ==>利用次数、不采用死循环
//2.标志位 ==> flag
//3.不用stop()、destroy()
class MyThreadStop implements Runnable{

    //标志位
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;

        while (flag){
            System.out.println("Run...." + i++);
        }
    }

    //自己定义的stop方法、对外提供方法改变标志位
    public  void stop(){
        this.flag=false;
    }
}


public class Test  {



    public static void main(String[] args) {

            MyThreadStop stop = new MyThreadStop();

            new Thread(stop).start();

        for (int i = 0; i < 500; i++) {
            System.out.println("main..."+i);

            if (i == 400){
                stop.stop();
                System.out .println("线程该停止了");
            }

        }

    }
}

线程休眠

​ 语法形式:

xxx.sleep(millis)

​ xxx线程休眠 x 毫秒

注:

​ sleep 指定当前线程阻塞多少毫秒

​ sleep存在 InterruptedException 异常

​ sleep时间达到后进入 就绪状态

​ 可以模拟网络延时,倒计时

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

​ 案例:模拟倒计时

public class Test  {
    public static void main(String[] args) {
        try {
            numsDown(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //模拟倒计时
    public static void numsDown(int nums) throws InterruptedException {
        while (true){
            Thread.sleep(1000);
            System.out.println(nums--);
            if (nums<=0) break;
        }
    }
}

线程礼让

​ 让当前线程暂定、但不造成阻塞

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

​ 注:

​ 由于 是由CPU重新调度,所以 不一定礼让成功

class MyYield implements Runnable{

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



public class Test  {
    public static void main(String[] args) {
        new Thread(new MyYield(),"Tom").start();
        new Thread(new MyYield(),"Jerry").start();

        /*
            礼让成功:
                Tom 线程开始执行
                Jerry 线程开始执行
                Tom线程停止执行
                Jerry线程停止执行

        */
    }


}

线程强制执行

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

class ThreadJoin implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("Join最强 => "+i);
        }
    }
}



public class Test  {
    public static void main(String[] args) throws InterruptedException {
        ThreadJoin join=new ThreadJoin();

        Thread thread = new Thread(join);
        thread.start();

        for (int i = 0; i < 10; i++) {
            if (i==5){
                thread.join();
            }
            System.out.println("main => " + i);
        }
        /*
            main => 0
            main => 1
            main => 2
            main => 3
            main => 4
            Join最强 => 0
            Join最强 => 1
            Join最强 => 2
            Join最强 => 3
            Join最强 => 4
            Join最强 => 5
            Join最强 => 6
            Join最强 => 7
            Join最强 => 8
            Join最强 => 9
            Join最强 => 10
            Join最强 => 11
            Join最强 => 12
            Join最强 => 13
            Join最强 => 14
            Join最强 => 15
            Join最强 => 16
            Join最强 => 17
            Join最强 => 18
            Join最强 => 19
            main => 5
            main => 6
            main => 7
            main => 8
            main => 9
         */
    }
}

线程状态观测

Thread.State
	New 
		尚未启动的线程
	Runnable
		在java虚拟机执行的线程
     Blocked
     	被阻塞等待监视器锁定的线程
     Waiting
     	正在等待另一个线程执行特定动作的线程
     Timed_Waiing
     	正在等待另一个线程执行动作到达指定等待时间的线程
     Terminated
     	已退出的线程
public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread.State state = thread.getState();
        System.out.println(state); //NEW

        thread.start();
        state=thread.getState();
        System.out.println(state); //RUNNABLE

        while (state != Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);
            /*
                TIMED_WAITING
                TIMED_WAITING  =>因为在run时 Thread.sleep(300);
                TERMINATED
             */

        }
    }

线程优先级

​ java提供 线程调度器 来监控 就绪状态的 所有线程

​ 优先级用数字表示:1~10

​ Thread.MIN_PRIORITY = 1;

​ Thread.MAX_PRIORITY = 10;

​ Thread.NORM_PRIORITY = 15;

​ 语法形式

getPriority.setPriority(int xxx)

注:

​ 优先级越高,启动概率越高

​ 一定要先设定优先级、再启动

public static void main(String[] args) throws InterruptedException {
        //主线程优先级
        System.out.println( Thread.currentThread().getName()+"==>"+Thread.currentThread().getPriority());

        ThreadPriority priority =new ThreadPriority();

        Thread t1 = new Thread(priority);
        Thread t2 = new Thread(priority);
        Thread t3 = new Thread(priority);
        Thread t4 = new Thread(priority);
        Thread t5 = new Thread(priority);

        //设置优先级
        t1.start();

        t2.setPriority(1);
        t2.start();

        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();

        /*
            main==>5
            Thread-2==>10
            Thread-0==>5
            Thread-1==>1
         */


    }

守护线程 daemon

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

​ 虚拟机 必须确保用户现场执行完毕、但不用等待守护线程执行完毕

xxx.setDaemon(true); //默认是fasle,即用户线程

线程同步

​ 多个线程控制一个资源

​ 处理多线程时,多个线程访问同一个对象,并且某些线程想修改对象,此时则需要线程同步。

​ 线程同步:一种等待机制,多个需要同时访问此对象的线程 进入 该对象 的 等待池 形成队列,等待前面线程使用完毕,下一个线程再使用。

队列和锁

​ 形成 线程同步 就需要 队列 + 锁

​ synchronized,当一个对象获得对象的排他锁,独占资源,其他线程就必须等待。

释放锁,会导致:

​ 一个线程持有锁会导致其他所有需要此锁的线程挂起

​ 在多线程竞争时,加锁,释放锁会引发性能问题

​ 优先级高 等待 优先级低 的 锁,会导致 优先级倒置,引发性能问题

不安全案例

​ 火车站买票案例

//不安全的买票
class BuyTicket implements Runnable{


    //票
    int ticketNums = 10;
    boolean flag = true;

    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        if (ticketNums <= 0){
            flag = false;
            return;
        }

        //模拟延时
        Thread.sleep(100);

        System.out.println(Thread.currentThread().getName()+" 买到 "+ticketNums--);
    }
}


public class Test  {
    public static void main(String[] args) throws InterruptedException {

        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Tom").start();
        new Thread(buyTicket,"Jerry").start();
        new Thread(buyTicket,"Jack").start();
    }


}

产生的问题:

​ 数据混乱

​ 产生拿到 -1

​ 不同线程拿到 同一张

​ 产生原因:每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

银行取钱问题

class Account{
    int money;
    String name;

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

class Drawing extends Thread{

    private Account account;
    private int drawingMoney;
    private int nowMoney;

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

    @Override
    public void run() {
        //判断有没有钱
        if (account.money - drawingMoney < 0 ){
            System.out.println(this.getName()+" 余额不足");
            return;
        }


        //sleep可以放大问题的可能性
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(account.name+" 余额: "+account.money);

        //账户的资金变动
        account.money = account.money -drawingMoney;
        //用户拿到的钱数
        nowMoney = nowMoney +drawingMoney;



        System.out.println(this.getName()+"手里的钱"+nowMoney);
    }
}

public class Test  {
    public static void main(String[] args) throws InterruptedException {
        Account account = new Account(100,"零花钱");


        Drawing drawing = new Drawing(account,50,"Tom");
        Drawing drawing1 = new Drawing(account,100,"Jerry");

        drawing.start();

        drawing1.start();

        /*
            零花钱 余额: 100
            Tom手里的钱50
            零花钱 余额: 100
            Jerry手里的钱100
         */


    }
}

产生问题:

​ 两者都看到同样的余额,取出来的钱总数会大于 额数。

synchronized机制

​ 在此处通过锁机制 synchronized 来保证数据在方法中被访问时的正确性。

synchronized 包括两种用法:

同步方法
public synchronized void method(int args){}

​ synchronized方法控制对 “对象”的访问,每个对象都对应着 一把锁,每个方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得该锁,继续执行。

缺点: 若将一个大的方法申明为synchronized 将会影响效率

eg:火车票案例改进

class BuyTicket implements Runnable{


    //票
    int ticketNums = 10;
    boolean flag = true;

    @Override
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //锁的是this
    private synchronized void buy() throws InterruptedException {
        if (ticketNums <= 0){
            flag = false;
            return;
        }

        //模拟延时
        Thread.sleep(100);

        System.out.println(Thread.currentThread().getName()+" 买到 "+ticketNums--);
    }
}


public class Test  {
    public static void main(String[] args) throws InterruptedException {

        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket,"Tom").start();
        new Thread(buyTicket,"Jerry").start();
        new Thread(buyTicket,"Jack").start();

        /*
            Tom 买到 10
            Tom 买到 9
            Jack 买到 8
            Jerry 买到 7
            Jerry 买到 6
            Jack 买到 5
            Jack 买到 4
            Tom 买到 3
            Jack 买到 2
            Jerry 买到 1
         */
    }


}
同步块
synchronized(Obj){}

​ Obj:同步监视器

​ 可以是任意对象,但推荐使用共享资源作为同步监视器

​ 同步方法无需指定监视器,因为同步方法的同步监视器就是 this(对象本身)

eg: 银行取钱的问题

package javaEE;


import java.io.BufferedWriter;
import java.util.concurrent.Callable;


class Account{
    int money;
    String name;

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

class Drawing extends Thread{

    private Account account;
    private int drawingMoney;
    private int nowMoney;

    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(this.getName()+" 余额不足");
                return;
            }

            //sleep可以放大问题的可能性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(account.name+" 余额: "+account.money);

            //账户的资金变动
            account.money = account.money -drawingMoney;
            //用户拿到的钱数
            nowMoney = nowMoney +drawingMoney;



            System.out.println(this.getName()+"手里的钱"+nowMoney);
        }


    }
}

public class Test  {
    public static void main(String[] args) throws InterruptedException {
        Account account = new Account(100,"零花钱");


        Drawing tomDrawing = new Drawing(account,50,"Tom");
        Drawing jerryDrawing = new Drawing(account,100,"Jerry");

        tomDrawing.start();

        jerryDrawing.start();

        /*
            零花钱 余额: 100
            Tom手里的钱50
            零花钱 余额: 100
            Jerry手里的钱100
         */


    }
}

死锁

​ 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才运行,而导致多个线程都停止,互相等待释放。

​ 即某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题

​ 死锁产生的必要条件:

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

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

​ 3.不剥夺条件:进程已获得的资源,在未完成前,不得强行

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

避免死锁,只需要避免以上条件中的一条或多条即可

Lock锁

​ 通过显式定义同步锁对对象来实现同步。同步锁使用Lock对象充当。

Lock接口及相关实现类

interface Lock //Lock接口
	class ReentrantLock //拥有与synchronized相同的并发性和内存语句
	class ReentrantLock //可以显示加锁、释放锁

eg:

class LockDemo 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(); //解锁
            }
            }



    }
}


public class Test  {
    public static void main(String[] args) throws InterruptedException {
        LockDemo lockDemo = new LockDemo();

        new Thread(lockDemo).start();
        new Thread(lockDemo).start();
        new Thread(lockDemo).start();
    }
}

注:

​ Lock是显式锁(需手动 开启、关闭锁) synchronized 是隐式锁(出了作用域便释放了)

​ Lock只有代码块锁

​ 使用Lock锁,JVM可更快的调度线程

​ 推荐使用顺序:

​ Lock > 同步代码块 > 同步方法

线程通信

​ 主要应用的是:

Thread.wait(); //等待被唤醒
Thread.notifyAll(); //唤醒线程

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

​ 1.比如 仓库只存放一件产品,生产者负责放入,消费者负责取出

​ 2.若仓库没有产品,生产者放入,然后停止生产,直到仓库的产品被取出

​ 3.若仓库有产品,消费者取出,然后停止消费,直到仓库的产品被生产者放入

管程法

​ 通过缓冲区

//生产者
class Producer extends Thread{
    Warehouse warehouse;

    public Producer(Warehouse warehouse){
        this.warehouse=warehouse;
    }

    //生产

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("生产了 "+ i + " 个产品");
            warehouse.push(new Product(i));
        }

    }
}

//消费者
class Consumer extends Thread{
    Warehouse warehouse;

    public Consumer(Warehouse warehouse){
        this.warehouse=warehouse;
    }

    //消费
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("消费了 "+ warehouse.pop().id+ " 个产品");

        }
    }
}

//产品
class Product{
    int id;

    public Product(int id) {
        this.id = id;
    }
}

//仓库(缓冲区)
class Warehouse{

    //能容纳多少
    Product[] products = new Product[10];
    //当前产品有多少
    int count = 0;

    //生产者投入产品
    public synchronized void push(Product product){
        //如果仓库满了,则需要等待消费者消费
        if (count == products.length){
            //通知消费者消费
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        //如果没有满,则需要生产者放入
        products[count] = product;
        count++;

        //通知消费者消费
        this.notifyAll();
    }

    //消费者消费
    public synchronized Product pop(){
        //判断能否消费
        if (count==0){
            //等待生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //消费
        count--;
        Product product = products[count];


        this.notifyAll();
        return product;

    }
}



public class Test  {
    public static void main(String[] args) throws InterruptedException {
        Warehouse warehouse = new Warehouse();

        Producer producer = new Producer(warehouse);
        Consumer consumer = new Consumer(warehouse);

        producer.start();
        consumer.start();

    }
}

信号灯法

​ 通过标志位

//生产者
class Producer extends Thread{
    Product product;

    public Producer(Product product){
        this.product=product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i%2==0){
                this.product.push("苹果手机");
            }else {
                this.product.push("谷歌手机");
            }
        }
    }
}

//消费者
class Consumer extends Thread{
    Product product;

    public Consumer(Product product){
        this.product=product;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            this.product.pop();
        }
    }
}

//产品
class Product{

    String name;

    //生产者生产、消费者等待 T
    //消费者取出、生产者生产 F
    boolean flag = true;

    //生产者 放入
    public synchronized void push(String name){
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("生产者生产了 "+name);

        //通知消费者消费
        this.notifyAll();
        this.name=name;
        this.flag = !this.flag;
    }

    //消费者 取出
    public synchronized void pop(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("消费者购买了"+this.name);

        //通知生产者生产
        this.notifyAll();
        this.flag = !this.flag;
    }
}




public class Test  {
    public static void main(String[] args) throws InterruptedException {
        Product product = new Product();

        new Producer(product).start();
        new Consumer(product).start();

    }
}

线程池

​ 出现的背景:

​ 经常创建或销毁、使用量特别大的资源时,对性能的影响较大

​ 思路:

​ 提前创建线程,放入线程池,需要时取出,不需要时放回。可以避免频繁创建销毁、实现重复利用。

​ 好处:

​ 提高了响应速度

​ 降低资源消耗

​ 便于线程管理

​ corePoolSize: 线程池的大小

​ maximumPoolSize:最大线程数

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

相关线程池类

ExecutorService -> interface
	void execute(Runnable command):执行命令,没有返回值,一般用于执行Runnable
	<T> Future<T> submit(Callable<T> task):执行任务,有返回值。一般用来执行Callable
	void shutdown():关闭线程池
	
Executors -> class
	用于创建并返回不同类型的线程池

eg:

class ThreadGo implements Runnable{

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



public class Test  {
    public static void main(String[] args) throws InterruptedException {
        //1.创建服务,创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);

        //线程池创建线程
        service.execute(new ThreadGo());
        service.execute(new ThreadGo());
        service.execute(new ThreadGo());
        service.execute(new ThreadGo());
        service.execute(new ThreadGo());

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


    }
}
资源下载链接为: https://pan.quark.cn/s/3d8e22c21839 随着 Web UI 框架(如 EasyUI、JqueryUI、Ext、DWZ 等)的不断发展与成熟,系统界面的统一化设计逐渐成为可能,同时代码生成器也能够生成符合统一规范的界面。在这种背景下,“代码生成 + 手工合并”的半智能开发模式正逐渐成为新的开发趋势。通过代码生成器,单表数据模型以及一对多数据模型的增删改查功能可以被直接生成并投入使用,这能够有效节省大约 80% 的开发工作量,从而显著提升开发效率。 JEECG(J2EE Code Generation)是一款基于代码生成器的智能开发平台。它引领了一种全新的开发模式,即从在线编码(Online Coding)到代码生成器生成代码,再到手工合并(Merge)的智能开发流程。该平台能够帮助开发者解决 Java 项目中大约 90% 的重复性工作,让开发者可以将更多的精力集中在业务逻辑的实现上。它不仅能够快速提高开发效率,帮助公司节省大量的人力成本,同时也保持了开发的灵活性。 JEECG 的核心宗旨是:对于简单的功能,可以通过在线编码配置来实现;对于复杂的功能,则利用代码生成器生成代码后,再进行手工合并;对于复杂的流程业务,采用表单自定义的方式进行处理,而业务流程则通过工作流来实现,并且可以扩展出任务接口,供开发者编写具体的业务逻辑。通过这种方式,JEECG 实现了流程任务节点和任务接口的灵活配置,既保证了开发的高效性,又兼顾了项目的灵活性和可扩展性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值