Java并发基础:线程的创建
线程的创建和管理:
1.应用Thread类显式创建、管理线程
2.应用Executor创建并管理线程。
定义任务:
无返回的任务:实现Runnable接口并编写run()方法。
有响应的任务:实现Callable接口并编写call()方法。
如下的火箭发射倒计时任务:
public class Lunch implements Runnable {
int countDown = 9;
int taskCount = 0;
int rocketNum = 9;
final int id = taskCount++;
final static Logger log = Logger.getLogger("lavasoft");
Logger log1 = Logger.getLogger("lavasoft");
Logger log2 = Logger.getLogger("lavasoft.blog");
public Lunch(){
}
public Lunch(int countDown,int rocketNum){
this.countDown=countDown;
this.rocketNum=rocketNum;
}
public void status(int rocketNum){
while(countDown>=0){
if(countDown==0){
log.info("火箭"+rocketNum+"发射成功!");
countDown--;
}else{
log.info("火箭"+rocketNum+"将在"+countDown+"秒后发射!");
countDown--;
}
}
}
@Override
public void run() {
// TODO Auto-generated method stub
status(rocketNum);
}
public static void main(String args[]) throws SecurityException, IOException{
FileHandler fileHandler = new FileHandler("C:/testlog.log");
fileHandler.setLevel(Level.INFO);
fileHandler.setFormatter(new MyLogHander());
ExecutorService exec = Executors.newCachedThreadPool();// 需要多少线程创建多少线程,用多少给多少。
ExecutorService exec2 = Executors.newSingleThreadExecutor();// 保证任意时刻任何线程中都只有唯一的任务在运行。
ExecutorService exec3 = Executors.newFixedThreadPool(2);//指定线程数量。
ExecutorService exec4 = Executors.newScheduledThreadPool(2);//可实现周期性或延迟任务
log.addHandler(fileHandler);
for(int rocketNum=1;rocketNum<10;rocketNum++){
//用Thread类显式创建并管理线程
Thread t1 = new Thread(new Lunch(6,rocketNum));
t1.start();
//用Executor类创建并管理线程
exec.execute(new Lunch(6,rocketNum));
exec2.execute(new Lunch(6,rocketNum));
exec3.execute(new Lunch(6,rocketNum));
exec4.execute(new Lunch(6,rocketNum));
log.info("等待火箭"+rocketNum+"发射");
}
exec.shutdown();
}
}
class MyLogHander extends Formatter{
@Override
public String format(LogRecord record) {
return record.getLevel() + ":" + record.getMessage()+"\n";
}
}
public class Lunch implements Callable<String> {
int countDown = 9;
int taskCount = 0;
int rocketNum = 9;
final int id = taskCount++;
final static Logger log = Logger.getLogger("lavasoft");
Logger log1 = Logger.getLogger("lavasoft");
Logger log2 = Logger.getLogger("lavasoft.blog");
public Lunch(){
}
public Lunch(int countDown,int rocketNum){
this.countDown=countDown;
this.rocketNum=rocketNum;
}
public void status(int rocketNum){
while(countDown>=0){
if(countDown==0){
log.info("火箭"+rocketNum+"发射成功!");
countDown--;
}else{
log.info("火箭"+rocketNum+"将在"+countDown+"秒后发射!");
countDown--;
}
}
}
@Override
public String call() {
// TODO Auto-generated method stub
status(rocketNum);
return "***火箭"+rocketNum+"发射完毕***";
}
public static void main(String args[]) throws SecurityException, IOException{
FileHandler fileHandler = new FileHandler("C:/testlog.log");
fileHandler.setLevel(Level.INFO);
fileHandler.setFormatter(new MyLogHander());
ExecutorService exec = Executors.newCachedThreadPool();// 需要多少线程创建多少线程,用多少给多少。
ExecutorService exec2 = Executors.newSingleThreadExecutor();// 保证任意时刻任何线程中都只有唯一的任务在运行。
ExecutorService exec3 = Executors.newFixedThreadPool(2);//指定线程数量。
ExecutorService exec4 = Executors.newScheduledThreadPool(2);//可实现周期性或延迟任务
log.addHandler(fileHandler);
List<Future<String>> list = new ArrayList<Future<String>>();
for(int rocketNum=1;rocketNum<10;rocketNum++){
//用Thread类显式创建并管理线程
Thread t1 = new Thread(new Lunch(6,rocketNum));
t1.start();
//用Executor类创建并管理线程
exec.execute(new Lunch(6,rocketNum));
exec2.execute(new Lunch(6,rocketNum));
exec3.execute(new Lunch(6,rocketNum));
Future<String> a = exec.submit(new Lunch(6,rocketNum));//call方法会返回一个Future对象,与runnable不同,将任务赋予给线程时,必须用submit方法。
list.add(a);
try {
System.out.println(a.get());
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log.info("等待火箭"+rocketNum+"发射");
}
exec.shutdown();
}
}
class MyLogHander extends Formatter{
@Override
public String format(LogRecord record) {
return record.getLevel() + ":" + record.getMessage()+"\n";
}
}
总结:
Callable接口和Runnable接口相似,区别就是Callable需要实现call方法,而Runnable需要实现run方法;并且,call方法还可以返回任何对象,无论是什么对象,JVM都会当作Object来处理。但是如果使用了泛型,我们就不用每次都对Object进行转换了。
Runnable和Callable都是接口
不同之处:
1.Callable可以返回一个类型V,而Runnable不可以
2.Callable能够抛出checked exception,而Runnable不可以。
3.Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
4.Callable和Runnable都可以应用于executors。而Thread类只支持Runnable.
上面只是简单的不同,其实这两个接口在用起来差别还是很大的。Callable与executors联合在一起,在任务完成时可立刻获得一个更新了的Future。而Runable却要自己处理
Future接口,一般都是取回Callable执行的状态用的。其中的主要方法:
- cancel,取消Callable的执行,当Callable还没有完成时
- get,获得Callable的返回值
- isCanceled,判断是否取消了
- isDone,判断是否完成
用Executor来构建线程池,应该要做的事:
1).调用Executors类中的静态方法newCachedThreadPool(必要时创建新线程,空闲线程会被保留60秒)或newFixedThreadPool(包含固定数量的线程池)等,返回的是一个实现了ExecutorService接口的ThreadPoolExecutor类或者是一个实现了ScheduledExecutorServiece接口的类对象。
2).调用submit提交Runnable或Callable对象。
3).如果想要取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象。
4).当不再提交任何任务时,调用shutdown方法。
Java并发基础:线程的创建的更多相关文章
- Java并发基础--线程通信
java中实现线程通信的四种方式 1.synchronized同步 多个线程之间可以借助synchronized关键字来进行间接通信,本质上是通过共享对象进行通信.如下: public class S ...
- Java 并发基础——线程安全性
当线程安全:多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么久称这个类是线程安全的. 在线程 ...
- Java并发基础--线程安全
一.线程安全 1.线程安全的概念 线程安全:某个类被单个线程,或者多个线程同时访问,所表现出来的行为是一致,则可以说这个类是线程安全的. 2.什么情况下会出现线程安全问题 在单线程中不会出现线程安全问 ...
- java并发编程 线程基础
java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...
- Java并发编程:如何创建线程?
Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...
- Java并发编程:线程和进程的创建(转)
Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...
- 【转】Java并发编程:如何创建线程?
一.Java中关于应用程序和进程相关的概念 在Java中,一个应用程序对应着一个JVM实例(也有地方称为JVM进程),一般来说名字默认是java.exe或者javaw.exe(windows下可以通过 ...
- java并发基础(五)--- 线程池的使用
第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...
- 2、Java并发编程:如何创建线程
Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...
- Java 并发基础
Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...
随机推荐
- Vmware克隆Centos 不能上网的解决方案
问题:用Vmware克隆Centos 6.4后,发现系统内只有eth1,而且/etc/sysconfig/network-scripts/下只有,ifcfg-eth0文件,虽然可以上网,但无法设置静态 ...
- 文件格式——gff格式
Gff文件格式 gff格式是Sanger研究所定义,是一种简单的.方便的对于DNA.RNA以及蛋白质序列的特征进行描述的一种数据格式,已经成为序列注释的通用格式,比如基因组的基因预测,许多软件都支持输 ...
- p2341&bzoj1051 受欢迎的牛
传送门(洛谷) 传送门(bzoj) 题目 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C ...
- vue.js基础学习(1)
一:v-cloak:解决浏览器闪烁,编译过程中不会显示,直到编译结束才显示. 用法:[v-cloak] { display: none;} <div v-cloak> {{ message ...
- eos命令
ps -ef|grep javakill -9 端口号cd /opt/sudytrue>nohup.outnohup eos7.5/startServer.sh &
- 【转】Subversion快速入门教程-动画演示
如何快速建立Subversion服务器,并且在项目中使用起来,这是大家最关心的问题,与CVS相比,Subversion有更多的选择,也更加的容易,几个命令就可以建立一套服务器环境,可以使用起来,这里配 ...
- Protocol Buffers官方文档(开发指南)
本文是对官方文档的翻译,然后截取了一篇非常优秀的文章片段来帮助理解,本人英文水平有限,基本都是直译,如果有不理解的地方请参考英文官方文档,参考的文章链接在文章末尾 protocol buffers简介 ...
- Mysql导入导出数据库11111
导出: 通过命令行 在MYSQL中的bin文件夹的目录下 输入:D:\phpStudy\MySQL\bin>mysqldump -uroot -p 数据库名 > 导出的文件名 导入: 需 ...
- JavaScript -- 常用的数组及字符串方法
数组 var arr= new Array(); arr.push(); //在数组尾部添加一个元素,返回新的长度 *原数组发生变化 arr.pop(); //删除最后一个元素,返回的是被删除的元素 ...
- 2017乌鲁木齐区域赛I(带权并查集)
#include<bits/stdc++.h>using namespace std;int f[200010];//代表元long long rl[200010];//记rl[i]为结点 ...