java中,启动线程通常是通过Thread或其子类通过调用start()方法启动。
 常见使用线程有两种:实现Runnable接口和继承Thread。而继承Thread亦或使用TimerTask其底层依旧是实现了Runnabel接口。考虑到java的单继承的限制,所以在开发过程中大部分情况在使用线程的时候是通过实现Runnabel接口或者Runnbel匿名类来实现的。
 例如:

package com.zpj.thread.blogTest;
/**
* Created by PerkinsZhu on 2017/8/11 16:42.
*/
public class ThreadTest { public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
//所有的这些启动方式的执行体都是在run方法中完成的
threadTest.testLambda();
threadTest.testRunnableWithAnonymousRunnable();
threadTest.testRunnableWithAnonymousThread();
threadTest.testRunnable();
threadTest.testMyThread();
} public void testLambda() {//lambda表达式开启线程 jdk1.8中的特性
new Thread(() -> System.out.println("i am lambda Thread....")).start();
} public void testRunnableWithAnonymousThread() {//匿名Thread类开启线程
new Thread() {
@Override
public void run() {
System.out.println("i am ThreadWithAnoymous");
}
}.start();
} public void testRunnableWithAnonymousRunnable() {//匿名Runnable类开启线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("i am RunableWithAnoymous");
}
});
thread.start();
} public void testRunnable() {//实现Runnable接口
MyRunnable runable = new MyRunnable();
Thread thread = new Thread(runable);
thread.start();
} public void testMyThread() {//继承自Thread
MyThread thread = new MyThread();
thread.setName("MyThread");
thread.start();
}
} class MyRunnable implements Runnable {//实现Runnable接口 @Override
public void run() {
System.out.println("i am MyRunnable");
}
} class MyThread extends Thread {//继承Thread @Override
public void run() {
System.out.println(" i am MyThread!!");
}
}

注意,直接调用run()方法的方式执行线程体并未开启新线程,只是在main方法中调用了一个普通方法而已。而使用start()方法则会开启一个新的线程执行。两者的区别主要表现在前者是阻塞式的,而后者为非阻塞式。

例如:

    public void testStartAndRun(){
MyThread thread = new MyThread();
thread.setName("MyThread");
thread.start();//start启动两者异步非阻塞运行
while (true){
System.out.println("---- "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread {//继承Thread @Override
public void run() {
while(true){
System.out.println("=== "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

运行结果如下:

---- main
==== MyThread
---- main
==== MyThread
==== MyThread
---- main
==== MyThread
---- main

而把thread.start() 修改为thread.run();之后,则如下

==== main
==== main
==== main
==== main
==== main
==== main

这里之所以线程名称为main是因为是在main线程中调用的run方法,所以打印出来的是===main。而thread.run();语句下面的循环则永远不会执行,程序将会一直在run方法中循环下去。

那么调用start方法,程序都做了些什么呢?看一下底层实现。

    public synchronized void start() {
//验证线程的状态
if (threadStatus != 0) {//这里的验证涉及到线程不能重复启动的问题,线程多次调用start则会抛出该异常
throw new IllegalThreadStateException();
}
//把该线程加入到线程组中
group.add(this);
boolean started = false;//标识线程是否启动成功
try {
start0();//调用native方法启动线程 该方法是阻塞的,程序等待其完成之后执行下面语句如果执行失败则直接抛出异常进入finally。
started = true;//修改线程启动状态
} finally {
try {
if (!started) {//启动失败,则移出线程组
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
} private native void start0();//native方法启动线程

通过Runnable启动具有一定的局限,执行线程没有返回值,无法捕获异常。在有些特殊情况下需要线程返回结果的时候就不太合适。这时可以选择Callable接口来完成。Callable涉及到Future模型,这到后面再说。

=============================================

原文链接:多线程(三) java中线程的简单使用 转载请注明出处!

=============================================

-----end

多线程(三) java中线程的简单使用的更多相关文章

  1. Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞

    Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...

  2. Java多线程并发03——在Java中线程是如何调度的

    在前两篇文章中,我们已经了解了关于线程的创建与常用方法等相关知识.接下来就来了解下,当你运行线程时,线程是如何调度的.关注我的公众号「Java面典」了解更多 Java 相关知识点. 多任务系统往往需要 ...

  3. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  4. 面试官:Java中线程是按什么顺序执行的?

    摘要:Java中多线程并发的执行顺序历来是面试中的重点,掌握Java中线程的执行顺序不仅能够在面试中让你脱颖而出,更能够让你在平时的工作中,迅速定位由于多线程并发问题导致的"诡异" ...

  5. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...

  6. 多线程(五) java的线程锁

    在多线程中,每个线程的执行顺序,是无法预测不可控制的,那么在对数据进行读写的时候便存在由于读写顺序多乱而造成数据混乱错误的可能性.那么如何控制,每个线程对于数据的读写顺序呢?这里就涉及到线程锁. 什么 ...

  7. Java中线程池,你真的会用吗?

    在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...

  8. Java中线程和线程池

    Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...

  9. Java中线程池,你真的会用吗?ExecutorService ThreadPoolExcutor

    原文:https://www.hollischuang.com/archives/2888 在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及 ...

随机推荐

  1. Centos6增加新用户并赋予权限

    第一步:创建用户并设置密码 useradd testuser // 增加用户名为'testuser'的用户 passwd testpasswd //设定密码为'testpasswd' 第二步:用户授权 ...

  2. WEB服务器防盗链_HttpAccessKeyModule_Referer(Nginx&&PHP)

    盗链的概念指在自己的页面上展示一些并不在自己服务器上的内容.也就是获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容.如,小站盗用大站的图片.音乐.视频.软件等 ...

  3. EmguCv“线段” 结构类型学习

    1. 文件所在 Namespace: Emgu.CV.Structure Assembly: Emgu.CV (in Emgu.CV.dll) Version: 3.0.0.2157 (3.0.0.2 ...

  4. 《设计模式之禅》--设计模式大PK

    创建类模式包括工厂方法模式.建造者模式.抽象工厂模式.单例模式和原型模式. 其中单例模式要保持在内存中只有一个对象,原型模式是要求通过复制的方式产生一个新的对象. [工厂方法(抽象工厂) VS 建造者 ...

  5. UVA 1626 Brackets sequence 区间DP

    题意:给定一个括号序列,将它变成匹配的括号序列,可能多种答案任意输出一组即可.注意:输入可能是空串. 思路:D[i][j]表示区间[i, j]至少需要匹配的括号数,转移方程D[i][j] = min( ...

  6. HDU - 3567 Eight II (bfs预处理 + 康托) [kuangbin带你飞]专题二

    类似HDU1430,不过本题需要枚举X的九个位置,分别保存状态,因为要保证最少步数.要保证字典序最小的话,在扩展节点时,方向顺序为:down, left, right, up. 我用c++提交1500 ...

  7. hive:join操作

    hive的多表连接,都会转换成多个MR job,每一个MR job在hive中均称为Join阶段.按照join程序最后一个表应该尽量是大表,因为join前一阶段生成的数据会存在于Reducer 的bu ...

  8. Nginx反向代理实现Tomcat负载均衡

    这篇短文主要介绍Tomcat的集群和用Nginx反向代理实现Tomcat负载均衡. 1.首先需要对一些知识点进行扫盲(对自己进行扫盲,囧): 集群(Cluster) 简单来说就是用N台服务器构成一个松 ...

  9. 利用Caffe训练模型(solver、deploy、train_val)+python使用已训练模型

    本文部分内容来源于CDA深度学习实战课堂,由唐宇迪老师授课 如果你企图用CPU来训练模型,那么你就疯了- 训练模型中,最耗时的因素是图像大小size,一般227*227用CPU来训练的话,训练1万次可 ...

  10. DriverStudio 和 WDF驱动 通过GUID获取设备句柄的差别

    DriverStudio /***************************************************************************** * 功能: 通过 ...