java-线程

Java线程

1、线程的创建方式

  • 集成Thread类
package com.example.learning.thread;

import lombok.extern.slf4j.Slf4j;

/**
 * @author solin.jiang
 * @Description
 * @create 2020-11-24 16:25
 *
 * java 线程的实现和创建方式
 *
 * Java线程的创建方式:
 *  1、继承Thread类(Thread的本质也是实现了Runnable接口)
 *  2、实现Runnable接口
 *  3、实现Callable接口,
 *
 *  start()方法启动一个线程
 *  run()方法仅仅是类中的一个方法
 *  
 *  通过集成Thread类创建线程
 */
@Slf4j
public class MyThread extends Thread {

    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        log.info("this is myThread...Name:{}", thread.getName());
    }

    public static void main(String[] args) throws InterruptedException{
        Thread thread = Thread.currentThread();

        MyThread myThread = new MyThread();
        myThread.start();
//        myThread.run();
        log.info("this is main...Name:{}",thread.getName());
    }
}
  • 实现Runnable接口
package com.example.learning.thread;

import lombok.extern.slf4j.Slf4j;

/**
 * @author solin.jiang
 * @Description
 * @create 2020-11-24 17:50
 * 通过实现Runnable接口创建线程
 */
@Slf4j
public class MyThread2 implements Runnable {
    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        log.info("MyThread2 implements Runnable...Name:{}",thread.getName());
    }

    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread thread1 = new Thread(myThread2);
        thread1.start();
        Thread thread = Thread.currentThread();
        log.info("this is main...Name:{}",thread.getName());

    }
}
  • 实现Callable接口
package com.example.learning.thread;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author solin.jiang
 * @Description
 * @create 2020-11-24 17:58
 *
 * 从继承Thread类和实现Runnable接口可以看出,上述两种方法都不能有返回值,且不能声明抛出异常。
 * 而Callable接口则实现了此两点,Callable接口如同Runnable接口的升级版,其提供的call()方法将作为线程的执行体,同时允许有返回值。
 *
 * 但是Callable对象不能直接作为Thread对象的target,因为Callable接口是 Java 5 新增的接口,不是Runnable接口的子接口。
 * 对于这个问题的解决方案,就引入 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,
 * 可以作为Thread对象的target 。并且, Future 接口提供了一个实现类:FutureTask 。
 *
 * FutureTask实现了RunnableFuture接口,可以作为 Thread对象的target。
 */
@Slf4j
public class MyThread3{
    public static void main(String[] args) {
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
            int i = 0 ;
            for(;i<100;i++){
                log.info("{}的循环变量i的值:{}",Thread.currentThread().getName(),i);
            }
            return i;
        });

        for(int i=0;i<100;i++){
//            log.info("{}的循环变量i:{}",Thread.currentThread().getName(),i);
            if(i==20){
                new Thread(task,"有返回值的线程").start();
            }
        }
        try {
            log.info("返回值:{}",task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

线程池

package com.example.learning.thread;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author solin.jiang
 * @Description
 * @create 2020-11-25 09:43
 *
 * newFixedThreadPool,newCachedThreadPool只是把ThreadPoolExecutor进行了封装而已,
 * 所以建议直接使用ThreadPoolExecutor而不是这些封装类
 *
 */
@Slf4j
public class MyThreadPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        while (true){
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("当前线程的名称:{}",Thread.currentThread().getName());
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}
  • 使用阿里推荐的方式:ThreadPoolExecutor 创建线程池

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

package com.example.learning.thread;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * @author solin.jiang
 * @Description
 * @create 2020-11-25 10:00
 *
 * 使用 ThreadPoolExecutor 创建线程池
 *
 * ThreadPoolExecutor的7个参数:
 * 1、corePoolSize:核心线程数
 *    核心线程会一直存活,及时没有任务需要执行
 *    当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
 *    设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
 * 2、maximumPoolSize:最大线程数
 *    当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
 *    当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
 * 3、keepAliveTime:线程空闲时间
 *    当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
 *    如果allowCoreThreadTimeout=true,则会直到线程数量=0
 * 4、unit:时间单位
 *    空闲线程存活时间的单位,如TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。
 * 5、workQueue:任务队列
 *    工作队列(阻塞队列),简单来说,队列的容量决定了能有多少请求被阻塞队列接受。线程池达到最大线程数在处理请求,接下来的请求就会被放入阻塞队列等待处理。
 * 6、threadFactory:
 *    线程工厂,一般使用默认Executors.defaultThreadFactory()即可。
 * 7、handler:线程池的拒绝策略
 *    当等待队列已经满了,再也塞不下新的任务,同时,线程池也达到max线程了,无法为新任务服务,这时,我们需要拒绝策略机制合理的处理这个问题。TODO(了解拒绝策略机制)
 */
@Slf4j
public class MyThreadPool2 {

    public static void main(String[] args) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("demo-pool-%d").build();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,15,5000,
                TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(), namedThreadFactory);

        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("当前线程的名称:{}",Thread.currentThread().getName());
            }
        });
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值