java并发编程(一)-线程池

6 篇文章 0 订阅
3 篇文章 0 订阅

概要:对于线程理解一直的不深,这篇文章参考《java编程思想》并发这一章节的思路,稍微深入的梳理线程知识,例子来源主要是书上的练习题。不过由于原书篇幅较长,所以这篇文章主要梳理基本的线程机制这一小节。

  • 定义任务

练习一:实现一个Runnable接口。在run()内部打印一个消息,然后调用yield()。重复这个操作三次,然后从run()中返回。在构造器中放置一条启动消息,并且放置一条在任务终止时的关闭消息。使用线程创建大量的任务并驱动它们。

package twentyoneThread;
//实现Runnable接口
class ExcOne implements Runnable {
    private int countDown = 3;
    private static int taskCount = 0;
    private final int id = taskCount++;
    //在构造器中放置一条启动消息
    public ExcOne() {
        System.out.println(this+ "start" +id);
    }
       //run()内部打印一条消息
    public String Status() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "ExcOneOff!") + ").";

    }


    @Override
    public void run() {

        while (countDown-- > 0) {
            System.out.println(Status()); //run()打印消息
            Thread.yield();//调用yield()
        }

    }

}

public class TestExcOne {
    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {
            new Thread(new ExcOne()).start();

        }

    }
}

输出式样:

twentyoneThread.ExcOne@15db9742start0
twentyoneThread.ExcOne@6d06d69cstart1
twentyoneThread.ExcOne@7852e922start2
twentyoneThread.ExcOne@4e25154fstart3
twentyoneThread.ExcOne@70dea4estart4
#1(2).
#1(1).
#3(2).
#0(2).
#1(ExcOneOff!).
#2(2).
#3(1).
#4(2).
#0(1).
#2(1).
#4(1).
#0(ExcOneOff!).
#2(ExcOneOff!).
#4(ExcOneOff!).
#3(ExcOneOff!).

练习2:遵循generic/Fibonacci.java 的形式,创建一个任务,它可以产生由n个斐波那契数字组成的序列,其中n是通过任务的构造器而提供的。使用线程创建大量的这种任务并驱动它们。

package twentyoneThread;

import java.util.Arrays;

class ExcTwo implements Runnable {

    private final int n;
//构造器传入n
    public ExcTwo(int n) {
        this.n = n;

    }
//斐波那契数
    private  int getFibo(int n) {
        if (n == 1 || n == 2)
            return 1;
        else
            return getFibo(n - 1) + getFibo(n - 2);
    }
//生成斐波那契数组
    private int[] getFiboArray() {

        int[] fibos = new int[n];
        for (int i = 0; i < fibos.length; i++) {
            fibos[i] = getFibo(i+1);
        }
        return fibos;

    }

    @Override
    public void run() {
//打印斐波那契数组
        System.out.format("Fibo of %d : %s \n", n, Arrays.toString(getFiboArray()));

    }

}

public class TestExcTwo {

    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {
            new Thread(new ExcTwo(i+1)).start();

        }

    }
}

输出式样

Fibo of 2 : [1, 1] 
Fibo of 4 : [1, 1, 2, 3] 
Fibo of 5 : [1, 1, 2, 3, 5] 
Fibo of 3 : [1, 1, 2] 
Fibo of 1 : [1] 
  • 使用Executor

本段主要讨论FixedThreadPool,CachedThreadPool,SingleThreadExcutor三种形式。

FixedThreadPool可以一次性预先执行高昂的线程分配,因而也就可以限制线程的数量了。这样可以节约时 间,因为你不用为每个任务都固定的付出创建线程的开销。

CachedThreadPool在执行程序过程中通常会创建与所需要量相同的线程,然后在它回收旧线程时停止新建 线程,因此它是合理的Excutor的首选。

SingleThreadExcutor就像线程数量为1的FixedThreadPool。对于你希望在另一个线程中连续的运行的任何事物(长期存活的任务)来说,都是很有用的。

练习3: 使用各种不同类型的执行器重复练习1.
//三个线程池的测试方法为了方便就放一块了,如果想要得到正确的结果只能单独的跑,合在一起有问题,目前还不会解决,等以后对线程加深理解后再修改。
package twentyoneThread;

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

class ExcThree implements Runnable {
    private int countDown = 3;
    private static int taskCount = 0;
    private final int id = taskCount++;

    public String Status() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "ExcOneOff!") + ").";

    }

    public ExcThree() {
        System.out.println(this + "start" + id);
    }

    @Override
    public void run() {

        while (countDown-- > 0) {
            System.out.println(Status());
            Thread.yield();
        }

    }

}

public class TestExcThree {
    public static void main(String[] args) {
        //CachedThreadPool
        ExecutorService exec1 = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            exec1.execute(new ExcThree());

        }
        exec1.shutdown();
        System.out.println("------------------------------");
        ////FixedThreadPool
        ExecutorService exec2 = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            exec2.execute(new ExcThree());

        }
        exec2.shutdown();
        //SingleThreadExcutor
        System.out.println("------------------------------");
        ExecutorService exec3 = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            exec3.execute(new ExcThree());

        }
        exec3.shutdown();
    }
}
  • 从任务中产生返回值

Runnable是执行工作的独立任务,但是它不会返回任何值。如果你希望任务在完成时能够返回一个值,那么必须实现Callable接口而不是Runnable接口。

练习4:修改练习2,使得计算所有斐波那契赎罪的任务成为Callble,创建多个任务并显示结果.
//原书将斐波那契数字改为求和
package twentyoneThread;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
//继承Callable接口
class ExcFour implements Callable<String> {

    private final int n;

    public ExcFour(int n) {
        this.n = n;

    }

    private int getFibo(int n) {
        if (n == 1 || n == 2)
            return 1;
        else
            return getFibo(n - 1) + getFibo(n - 2);
    }

    private int[] getFiboArray() {

        int[] fibos = new int[n];
        for (int i = 0; i < fibos.length; i++) {
            fibos[i] = getFibo(i + 1);
        }
        return fibos;

    }
//调用call()方法
    @Override
    public String call() {
        return "Fibo of" + n + ":" + Arrays.toString(getFiboArray());

    }

}

public class TestExcFour {

    public static void main(String[] args) {
    //future对象的list
        ArrayList<Future<String>> lists = new ArrayList<Future<String>>();
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
 //调用submit方法
            lists.add(exec.submit(new ExcFour(i + 1)));

        }
        for (Future<String> future : lists) {
            try {
                System.out.println(future.get());//调用get方法
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            } finally {
                exec.shutdown();
            }

        }
    }
}

总结:篇幅貌似也不少,剩下的明天在写,最后做一个总结吧,本文主要讲述三个方面知识:线程的创建、多线程、Callable接口。具体定义及文字方面的详解参考《java编程思想》。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值