java线程(1)——三种创建线程的方式
前言
线程,英文Thread。在java中,创建线程的方式有三种:
1、Thread
2、Runnable
3、Callable
在详细介绍下这几种方式之前,我们先来看下Thread类和Runnable接口。
Runnable接口
接口中只有一个run()方法,等待实现类去实现。
package java.lang;
@FunctionalInterface
public interface Runnable { public abstract void run();
}
Thread类
该类实现了Runnable接口,也提供了很多其他的方法,如yield(),join()等
package java.lang;
public
class Thread implements Runnable {
//获取当前线程
public static native Thread currentThread();
public static native void yield();
//一系列的构造函数
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/*调用该方法时,jvm会调用run方法
*Causes this thread to begin execution; the Java Virtual Machine
* calls the run method of this thread.
*/
public synchronized void start() { if (threadStatus != 0)
throw new IllegalThreadStateException(); group.add(this); boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) { }
}
} }
一、实现Runnable接口
public class i_Runnable { /**
* 主线程main方法
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "====" + i);
if (i == 20) {
RunnableThreadTest rtt = new RunnableThreadTest();
//子线程
new Thread(rtt, "new Thread[1]====").start();
//new Thread(rtt, "新线程2").start();
}
} }
/**
* RunnableThreadTest实现Runnable接口
* @author YANG
*
*/
static class RunnableThreadTest implements Runnable {
private int i; @Override
public void run() {
for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
} } }
}
执行结果:
注意:
** 执行结果只截取了部分内容。
** 如果RunnableThreadTest类前不加static,会报错No enclosing instance of type i_Runnable is accessible. Must qualify the allocation with
an enclosin。因为只有内部类修饰为静态时,才可以在静态类方法(main方法)中调用该类的成员变量和方法。
二、继承Thread类
public class a_Thread {
public static void main(String[] args) {
Runner1 r=new Runner1();
r.start(); //已经有thread 不需要new,直接调用start即可。 for (int i = 0; i < 100; i++) {
System.out.println("main Thread:"+i);
}
} //Runner1继承Thread类,重写run方法
static class Runner1 extends Thread{
@Override
public void run() { for (int i = 0; i < 100; i++) {
System.out.println("Runner1:"+i);
} } }
}
思考:能不能将上面的r.start(); 改为 r.run();
分析:换成run()方法之后,就变成了普通的方法调用,只有一个主线程,没有子线程。
执行结果:为了方便显示,我们将循环次数改为10。
Runner1:0
Runner1:1
Runner1:2
Runner1:3
Runner1:4
Runner1:5
Runner1:6
Runner1:7
Runner1:8
Runner1:9
main Thread:0
main Thread:1
main Thread:2
main Thread:3
main Thread:4
main Thread:5
main Thread:6
main Thread:7
main Thread:8
main Thread:9
三、实现Callable接口
前面两种方式是传统的线程技术中的内容,第三种方式Callable和Future是jdk1.5之后新增的。我们先来补充点东西,看看这种方式与之前的方式有什么联系。
//实现Callable接口
public class j_CallableTest implements Callable<String> {
public static void main(String[] args) {
j_CallableTest test=new j_CallableTest();
FutureTask<String> ft=new FutureTask<>(test); for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" i的值为="+i);
if(i==20){
new Thread(ft,"子线程").start();
}
}
} //重写call方法
@Override
public String call() throws Exception {
int i = 0;
String reString = "";
for (; i < 100; i++) {
reString = Thread.currentThread().getName() + " " + i;
System.out.println(reString);
}
return reString;
}
}
从上面可以看到,new Thread的方式还是用的public Thread(Runnable target, String name); 说明FutureTask也是Runnable类型的,他们之间的关系可以从下图中看出来。
那么,使用Callable和Future的方式有什么特点呢?
我们从他们的定义来看,Callable接口中只有一个方法,返回值为V。前两种方式都是返回void。
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
小结:
1、接口实现更灵活,java不支持多继承。在这方面,Runnable和Callable更有优势。
2、返回值问题。Runnable和Thread都不能有返回值,但Callable可以,而且支持多种类型的数据。
就这两点来看,新增的Callable和Future的实现方式优势十分明显啊。但是追到原理,其实这三种都可以归结为一种方式。
最新文章
- Redis学习总结(1)——数据持久化
- iOS APP开发的小知识(分享)
- 从python中copy与deepcopy的区别看python引用
- Oracle 给表添加主键和使ID自增、触发器、创建结构一样的表
- A Tour of Go Type conversions
- codevs 1066 引水入城
- Java坑一
- Oracle数据导入导出imp/exp(转)
- JavaScript之对象序列化详解
- .NET程序集1
- 未在本地计算机上注册“Microsoft.Ace.OleDB.12.0”
- Spark源码分析之Spark-submit和Spark-class
- 满汉全席[2-SAT]
- Unity3D中的shader基础知识
- 输入一个字母,是元音字母,则输出时元音字母*,否则,输出为辅音字母 	(元音字母有:a,e,i,o,u)
- PAT L2-016 愿天下有情人都是失散多年的兄妹
- 数据库操作中如何批量执行多个sql文件?
- BZOJ1895Pku3580 supermemo——非旋转treap
- 原生js的dom操作
- setInterval 和 setTimeout