第一章 Java多线程--线程的创建

目录

一、基本概念

1.1线程与进程的区别

1.1.1 什么是进程

 1.1.2 什么是线程

 1.1.3 进程和线程的区别

1.2 多线程

1.3 串行、并行、并发的区别

1.4 同步异步、阻塞非阻塞

二、线程的创建

2.1 继承Thread类 重写run方法

2.2 实现Runnable接口 重写run方法

2.3 实现Callable 重写call方法,配合FutureTask

2.4 基于线程池构建线程


一、基本概念

1.1线程与进程的区别

1.1.1 什么是进程

进程是指运行中的程序。 比如我们使用浏览器,需要启动这个程序,操作系统会给这个程序分配一定的资源(占用内存资源)。

 1.1.2 什么是线程

线程是CPU调度的基本单位,每个线程执行的都是某一个进程的代码的某个片段(一个进程中可能包含多个线程)。

 1.1.3 进程和线程的区别

  • 根本不同:进程是操作系统分配的资源,而线程是CPU调度的基本单位。
  • 资源方面:同一个进程下的线程共享进程中的一些资源。线程同时拥有自身的独立存储空间。进程之间的资源通常是独立的。
  • 数量不同:进程一般指的就是一个进程。而线程是依附于某个进程的,而且一个进程中至少会有一个或多个线程。
  • 开销不同:毕竟进程和线程不是一个级别的内容,线程的创建和终止的时间是比较短的。而且线程之间的切换比进程之间的切换速度要快很多。而且进程之间的通讯很麻烦,一般要借助内核才可以实现,而线程之间通讯,相当方面。
  • .......

1.2 多线程

多线程单个进程中同时运行多个线程。

多线程的作用:为了提高CPU的利用率。CPU的处理速度很快,处理任务时网络IO或磁盘IO需要等待,为避免等待CPU会在这期间调度其他线程。这样大大提高了程序的效率,提高用户体验。

多线程的局限

  • 如果线程数量特别多,CPU在切换线程上下文时,会额外造成很大的消耗。
  • 任务的拆分需要依赖业务场景,有一些异构化的任务,很难对任务拆分,还有很多业务并不是多线程处理更好。
  • 线程安全问题:虽然多线程带来了一定的性能提升,但是再做一些操作时,多线程如果操作临界资源,可能会发生一些数据不一致的安全问题,甚至涉及到锁操作时,会造成死锁问题。

1.3 串行、并行、并发的区别

什么是串行:

串行就是一个一个排队,第一个做完,第二个才能上。

什么是并行:

并行就是同时进行处理。(一起上!!!)

什么是并发:

这里提到的并发不是高并发,是多线程的并发概念(CPU调度线程)。CPU在短时间内,切换执行线程,就像并行一样,但是只是CPU高速切换。

并行包括并发。并行就是多核CPU同时调度多个线程,是真正的多线程同时执行。

单核CPU只能实现并发,无法实现并行。

1.4 同步异步、阻塞非阻塞

同步与异步:执行某个方法后,被调用者是否主动反馈信息

阻塞和非阻塞:执行某个方法后,调用者是否一直等待结果

同步阻塞:用锅烧水,水开了,不会主动通知。烧水开始后,需要一直等待。

同步非阻塞:用锅烧水,水开了,不会主动通知你。烧水开始后,不需要一直等待,可以处理其他事情,但是需要时不时查看水开了没。

异步阻塞:用壶烧水,水开后,会主动通知你。烧水开始后,需要一直等待水烧开。

异步非阻塞:用壶烧水,水开后,会主题通知你。烧水开始后,不需要一种等待,可以去处理其他事情。

异步非阻塞是处理效果最好的,可以很好地提升效率地处理多线程任务。

二、线程的创建

线程的创建,有的人说三种,有的说五种等等,但是普遍认为是三种。

2.1 继承Thread类 重写run方法

启动线程调用start方法,会创建一个新的线程,并执行线程任务。

如果直接调用run方法,这样是使用当前线程执行run方法中的逻辑。

public class Test {

    public static void main(String[] args) {
        Job t1 = new Job();
        t1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main:" + i);
        }
    }

}
class Job extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Job:" + i);
        }
    }
}

2.2 实现Runnable接口 重写run方法

public class Test {

    public static void main(String[] args) {
        IRunnable iRunnable = new IRunnable();
        Thread t1 = new Thread(iRunnable);
        t1.start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main:" + i);
        }
    }

}

class IRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("IRunnable:" + i);
        }

    }
}

常用使用方式

  • 匿名内部类方式:
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("匿名内部类:" + i);
        }
    }
});
  • lambda方式:
Thread t2 = new Thread(() -> {
    for (int i = 0; i < 100; i++) {
        System.out.println("lambda:" + i);
    }
});

2.3 实现Callable 重写call方法,配合FutureTask

Callable用于有返回结果的非阻塞的执行方法

同步非阻塞。

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1. 创建Callable
        ICallable iCallable = new ICallable();
        //2. 创建FutureTask,传入Callable
        FutureTask futureTask = new FutureTask(iCallable );
        //3. 创建Thread线程
        Thread t1 = new Thread(futureTask);
        //4. 启动线程
        t1.start();
        //5. 其他操作。。。
        //6. 获取结果
        Object count = futureTask.get();
        System.out.println("总和为:" + count);
    }
}

class ICallable implements Callable{

    @Override
    public Object call() throws Exception {
        int count = 0;
        for (int i = 0; i < 100; i++) {
            count += i;
        }
        return count;
    }
}

2.4 基于线程池构建线程

@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(10);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("MyExecutor-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

@Service
public class IService {

    private final ThreadPoolTaskExecutor executor;

    @Autowired
    public IService (ThreadPoolTaskExecutor executor) {
        this.executor = executor;
    }

    public void doSomething() {
        executor.execute(() -> {
            // 这里是你的任务代码
        });
    }
}

创建线程的方式有好几种,但是底层只有一种,实现Runnble

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值