认识Java多线程——线程、线程池的使用&CachedThreadPool、FixedThreadPool、SingleThreadExecutor的特性

为什么要使用线程?

在编程中,很大一部分问题都可以用顺序编程来解决。然而,对于某些问题,如果能够并行执行程序中的多个部分,就可以提高我们程序的执行效率,也就提升了程序的性能!Java编程语言支持并发编程(多线程编程)。并发编程使我们可以将程序划分为多个分离的、独立运行的任务。通过使用多线程机制,这些独立任务(也可以称为子任务)中每个都将由执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,单个进程可以拥有多个并发执行的任务。

打个比方:你的妈妈需要买生活用品、做饭、洗碗、扫地,本来妈妈亲历亲为需要2个小时完成所有事情,现在有了外卖小哥帮忙买生活用品、妈妈负责做饭、洗碗机器人负责洗碗、扫地机器人负责扫地,将原本2小时的工作量缩短到了半小时。

将原本妈妈这个主线程需要做的事情,拆分给外卖小哥,洗碗机器人,扫地机器人这三个线程。那效率绝对比之前高哇哈哈!

使用Java如何创建一个线程?

一般有两种方式:

1. 继承Thread类(此种方式不推荐使用,因为Java是单继承的,假如你的类继承了Thread类,将不能再继承其他类,在此也不再介绍如何继承Thread来完成线程的创建)

2. 实现Runnable接口,构造一个Thread对象,将Runnable对象传递给Thread,调用start()方法创建线程

举个栗子:

(1)编写Test1类实现Runnable接口:

package com.ws.concurrency.test1;

public class Test1 implements Runnable {
    @Override
    public void run() {

        System.out.println("Test1 is running..." + Thread.currentThread().getName());
    }
}

(2)调用start()创建线程

package com.ws.concurrency.test1;

public class Test1Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Test1());
            thread.start();
        }
        System.out.println("main is running..." + Thread.currentThread().getName());
    }
}

(3)执行结果(当然每个人的电脑都不同,CPU运行的状态不同会导致结果不同)

main is running...main
Test1 is running...Thread-0
Test1 is running...Thread-1
Test1 is running...Thread-2
Test1 is running...Thread-3
Test1 is running...Thread-6
Test1 is running...Thread-7
Test1 is running...Thread-8
Test1 is running...Thread-9
Test1 is running...Thread-4
Test1 is running...Thread-5

除了这种在main中显示得创建线程外,我们还可以使用Executor来完成对线程的创建,Executor在java.util.concurrent包下,它可以帮助我们管理Thread对象,从而简化并发编程。

CachedThreadPool

(1)上面栗子中的Test1类

package com.ws.concurrency.test1;

public class Test1 implements Runnable {
    @Override
    public void run() {
        // Thread.currentThread().getName()是获取当前执行run()线程的名字,
        // 我们不指定线程名字时,系统将自动给线程起名
        System.out.println("Test1 is running..." + Thread.currentThread().getName());
    }
}

(2)使用Executors调度器工具类创建CachedThreadPool实现线程的创建

package com.ws.concurrency.main;

import com.ws.concurrency.test1.Test1;

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

public class CachedThreadPool {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            cachedThreadPool.execute(new Test1());
        }
        cachedThreadPool.shutdown(); //防止新任务被提交给这个Executor,当前main方法中的shutdown()被调用之前提交的所有任务将继续运行
        System.out.println("CachedThreadPool-main is running..." + Thread.currentThread().getName());
    }
}

 (3)执行结果

Test1 is running...main
Test1 is running...pool-1-thread-2
Test1 is running...pool-1-thread-1
Test1 is running...pool-1-thread-3
Test1 is running...pool-1-thread-4
Test1 is running...pool-1-thread-5

可以看到CacheThreadPool为我们创建了5个线程。它在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新的线程。

FixedThreadPool

(1)上面栗子中的Test1类

package com.ws.concurrency.test1;

public class Test1 implements Runnable {
    @Override
    public void run() {
        // Thread.currentThread().getName()是获取当前执行run()线程的名字,
        // 我们不指定线程名字时,系统将自动给线程起名
        System.out.println("Test1 is running..." + Thread.currentThread().getName());
    }
}

(2)使用Executors调度器工具类创建FixedThreadPool实现线程的创建

package com.ws.concurrency.main;

import com.ws.concurrency.test1.Test1;

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

public class FixedThreadPool{
    public static void main(String[] args) {
        ExecutorService fixedThreadPool= Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            cachedThreadPool.execute(new Test1());
        }
        fixedThreadPool.shutdown(); //防止新任务被提交给这个Executor,当前main方法中的shutdown()被调用之前提交的所有任务将继续运行
        System.out.println("FixedThreadPool-main is running..." + Thread.currentThread().getName());
    }
}

 (3)执行结果

Test1 is running...pool-1-thread-1
Test1 is running...pool-1-thread-2
Test1 is running...pool-1-thread-3
Test1 is running...pool-1-thread-4
Test1 is running...pool-1-thread-5

 我们需要5个线程,在创建FixedThreadPool时传递给了它5这个参数,它创建了5个线程。那当我们传递3呢?

package com.ws.concurrency.main;

import com.ws.concurrency.test1.Test1;

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

public class FixedThreadPool{
    public static void main(String[] args) {
        ExecutorService fixedThreadPool= Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            cachedThreadPool.execute(new Test1());
        }
        fixedThreadPool.shutdown(); //防止新任务被提交给这个Executor,当前main方法中的shutdown()被调用之前提交的所有任务将继续运行
        System.out.println("FixedThreadPool-main is running..." + Thread.currentThread().getName());
    }
}

结果:

Test1 is running...pool-1-thread-2
Test1 is running...pool-1-thread-1
FixedThreadPool-main is running...main
Test1 is running...pool-1-thread-3
Test1 is running...pool-1-thread-1
Test1 is running...pool-1-thread-2

 可以看出,结果是3个线程帮我们完成了5个任务,复用了线程pool-1-thread-2和pool-1-thread-1。因此,使用它我们可以一次性预先执行代价高昂的线程分配,因而也就可以限制线程的数量,不用为每个任务都固定地付出线程创建的开销。

SingleThreadExecutor

还是在Test1的基础上修改

package com.ws.concurrency.test1;

public class Test1 implements Runnable {
    private static int id = 0;
    @Override
    public void run() {
        id ++;
        System.out.println("Test1 is running " + id + "..." + Thread.currentThread().getName());
    }
}

 MySingleThreadExecutor.java

package com.ws.concurrency.main;

import com.ws.concurrency.test1.Test1;

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

public class MySingleThreadExecutor {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            singleThreadExecutor.execute(new Test1());
        }
        singleThreadExecutor.shutdown(); //防止新任务被提交给这个Executor,当前main方法中的shutdown()被调用之前提交的所有任务将继续运行
        System.out.println("MySingleThreadExecutor-main is running..." + Thread.currentThread().getName());
    }
}

执行结果

MySingleThreadExecutor-main is running...main
Test1 is running 1...pool-1-thread-1
Test1 is running 2...pool-1-thread-1
Test1 is running 3...pool-1-thread-1
Test1 is running 4...pool-1-thread-1
Test1 is running 5...pool-1-thread-1

它相当于是newFixedThread(1),为我们生成数量为1的线程。而且不论你执行多少次,Test1 is running *** 的顺序始终不会改变,而且始终使用的是pool--thread-1的线程,SingleThreadExecutor执行任务按照它们的提交顺序。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值