首页 > 编程语言 > Java编程思想17

Java编程思想17

时间:2022-12-26 10:57:38浏览次数:45  
标签:Java Thread 17 LiftOff 编程 任务 线程 Executor public

第二十一章:并发
基本的线程机制
  并发编程使我们可以将程序划分为多个分离的、独立运行的任务。通过使用多线程机制,这些独立任务(也被称为子任务)中的每一个都将由执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,因此,单个进程可以拥有多个并发执行的任务,但是你的程序使得每个任务都好像有其自己的CPU一样。其底层机制是切分CPU时间,但通常你不需要考虑它。
  线程模型为编程带来了便利,它简化了在单一程序中同时交织在一起的多个操作的处理。在使用线程时,CPU将轮流给每个任务分配其占用时间“。每个任务都觉得自己在一直占用CPU,但事实上CPU时间是划分成片段分配给了所有的任务(例外情况是程序确实运行在多个CPU之上)。线程的一大好处是可以使你从这个层次抽身出来,即代码不必知道它是运行在具有一个还是多个CPU的机器上。所以,使用线程机制,是一种建立透明的、可扩展的程序的方法,如果程序运行的太慢,为机器增添一个CPU就很容易的加快程序的运行速度。多任务和多线程往往是使用多处理器系统的最合理方式。

定义任务
线程可以驱动任务,因此你需要一种描述任务的方式。

使用Runnable接口:要想定义任务,只需实现Runable接口并编写run()方法,使得该任务可以执行你的命令,例如,下面的LiftOff任务将显示发射之前的倒计时:

package concurrency;

/**
* @author Mr.Sun
* @date 2022年09月03日 10:14
*
* 演示通过实现Runnable接口定义任务
*
* <p>
* 显示发射之前的倒计时
* </p>
*/
public class LiftOff implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;

public LiftOff() {
}

public LiftOff(int countDown) {
this.countDown = countDown;
}

public String status() {
return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + "). ";
}

@Override
public void run() {
while (countDown-- > 0) {
System.out.print(status());
Thread.yield();
}
}

} ///:~

 

标识符id可以用来区分任务的多个实例,它是final的,因为它一旦被初始化之后就不希望被修改。任务的run()方法通常总会有某种形式的循环,使得任务一直运行下去直到不再需要,所以要设定跳出循环的条件(有一种选择是直接从run)返回)。通常,run()被写成无限循环的形式,这就意味着,除非有某个条件使得run()终止,否则它将永远运行下去(在本章后面将会看到如何安全地终止线程)。
  在run()中对静态方法Thread.yield()的调用是对线程调度器(Java线程机制的一部分,可以将CPU从一个线程转移给另一个线程)的一种建议,它在声明:"我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机。”这完全是选择性的,但是这里使用它是因为它会在这些示例中产生更加有趣的输出∶你更有可能会看到任务换进换出的证据。

  在下面的实例中,这个任务的run()不是由单独的线程驱动的,它是在main()中直接调用的(实际上,这里仍旧使用了线程,即总是分配给main()的那个线程)∶

package concurrency;

/**
* @author Mr.Sun
* @date 2022年09月03日 10:23
*/
public class MainThread {

public static void main(String[] args) {
LiftOff launch = new LiftOff();
launch.run();
}
} /* Output:
#0(9). #0(8). #0(7). #0(6). #0(5). #0(4). #0(3). #0(2). #0(1). #0(LiftOff!).
*///:~

 

Thread类:将Runnable对象转变为工作任务的传统方式是把它交给一个Thread构造器,下面的示例展示了如何使用Thread来驱动LiftOff对象:

package concurrency;

/**
* @author Mr.Sun
* @date 2022年09月03日 10:29
*
* 将Runnable对象转变为工作任务的传统方式是把它交给一个Thread构造器
*/
public class BasicThreads {

public static void main(String[] args) {
Thread t = new Thread(new LiftOff());
t.start();
System.out.println("Waiting for LiftOff");
}
} /* Output:
Waiting for LiftOff
#0(9). #0(8). #0(7). #0(6). #0(5). #0(4). #0(3). #0(2). #0(1). #0(LiftOff!).
*///:~

 

使用Executor
  Java SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。Executor允许你管理异步任务的执行,而无须显式地管理线程的生命周期。Executor在Java SE5/6中是启动任务的优选方法。
  我们可以使用Executor来代替在BasicThreads.java中显示地创建Thread对象。LiftOff 对象知道如何运行具体的任务,与命令设计模式一样,它暴露了要执行的单一方法。ExecutorService(具有服务生命周期的Executor,例如关闭)知道如何构建恰当的上下文来执行Runnable对象。在下面的示例中,CachedThreadPool将为每个任务都创建一个线程。注意,ExecutorService对象是使用静态的Executor方法创建的,这个方法可以确定其Executor类型∶

package concurrency;

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

/**
* @author Mr.Sun
* @date 2022年09月03日 16:04
*
* 使用Executor
*/
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.execute(new LiftOff());
}
exec.shutdown();
}
}/* Output:
#0(9). #1(9). #2(9). #3(9). #0(8). #4(9). #1(8). #2(8). #3(8). #0(7). #4(8). #1(7). #2(7). #3(7). #0(6). #4(7). #1(6). #2(6). #3(6). #0(5). #1(5). #4(6). #3(5). #1(4). #2(5). #4(5). #0(4). #1(3). #2(4). #3(4). #0(3). #4(4). #1(2). #2(3). #3(3). #0(2). #4(3). #1(1). #2(2). #3(2). #0(1). #4(2). #1(LiftOff!). #2(1). #3(1). #0(LiftOff!). #4(1). #2(LiftOff!). #3(LiftOff!). #4(LiftOff!).
*///:~

 

标签:Java,Thread,17,LiftOff,编程,任务,线程,Executor,public
From: https://www.cnblogs.com/LvJinshuai/p/17005212.html

相关文章

  • Java编程思想18
    从任务种产生返回值:Runnable是执行工作的独立任务,但是它不返回任何值。如果你希望在任务完成时能够返回一个值,那么可以实现Callable接口而不是Runnable接口。在JavaSE5中......
  • Java编程思想19
    共享受限资源1.不正确访问资源  考虑下面的例子,其中一个任务产生产生偶数,而其他任务消费这些数字。而这些消费者任务的唯一工作就是校验偶数的有效性packageconcurr......
  • 实现JNI的另一种方法:使用RegisterNatives方法传递和使用Java自定义类
    除了使用传统方法实现JNI外,也可以使用RegisterNatives实现JNI。和传统方法相比,使用RegisterNatives的好处有三点:1、C++中函数命名自由,不必像javah自动生成的函数声明那样,拘......
  • 【HMS Core】升级SDK报错app_id failed: java.io.FileNotFoundException: agconnect-s
    问题描述:升级推送服务最新版SDK报错app_idfailed:java.io.FileNotFoundException:agconnect-services.json问题分析:从日志来看,是没有找到agconnect-services.json文件。......
  • Java小白必会!Intellij IDEA安装、配置及使用详细教程
    一.前言所谓工欲善其事必先利其器,一个好的工具对工作效率的提升是有非常大的帮助的。而在咱们程序员开发时,一个好的集成开发工具对于提高我们的编码效率和编程体验来说也是......
  • Java版小米商城项目简介
    小米商城课程详情1.课程介绍本套课程主要是基于Servlet、HTML、JS、Ajax、JSP、MySQL、JDBC、Tomcat、微信支付等web技术,仿照小米商城来实现一个电子商城项目。注意:本课程配......
  • 1:Web开发入门-Java Web
    (目录)1.1什么是Web应用程序在Sun的JavaServlet规范中,对JavaWeb应用作了这样定义:“JavaWeb应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在......
  • java的异常体系图
    本文主要讲述java的异常体系图老韩图解:  自己理解: ......
  • 代码随想录算法训练营Day25|216. 组合总和 III、17. 电话号码的字母组合
    代码随想录算法训练营Day25|216.组合总和III、17.电话号码的字母组合216.组合总和III216.组合总和III与「77.组合」类似,但区别在于题干要求的变化:只使用数字1......
  • JavaVM & JNIEnv
    JNIEnv提供了大多数的JNI函数。你的本地方法都会接收JNIEnv作为第一个参数。JNIEnv用于本地线程存储。因此,你不能在线程间共享同一个JNIEnv。如果一个代码段没有其他方式获......