1.线程创建的方式常用有两种

1. 继承 Thread 类创建线程
2. 实现 Runnable 接口创建线程

2.Thread 和 Runnable的区别

Thread和Runnable的相同点:都是"多线程的实现方式”。
Thread和Runnable的不同点:Thread 是类,而Runnable是接口;Thread本身是实现了 Runnable 接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。通常,建议通过“Runnable”实现多线程!

3.Thread和Runnable的多线程示例(暂不考虑数据竞态)

继承Thread创建步骤
1. 定义Thread类的子类,并重写该类的run()方法,该方法为线程执行体
2. 创建Thread子类的实例,也就是创建了线程对象
3. 启动线程,通过调用线程对象的start()方法来启动线程
Thread创建代码
package concurrent;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @Description: 线程创建
* @Author: lizhouwei
* @CreateDate: 2018/5/20 16:17
* @Modify by:
* @ModifyDate:
*/
class MyThread extends Thread {
private AtomicInteger ticket = new AtomicInteger(10); @Override
public void run() {
for (int i = 1; i <= ticket.intValue(); i++) {
System.out.println(Thread.currentThread().getName() + " ticket " + i);
}
}
} public class ThreadDmo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
myThread1.start();
}
}
实现Runnable创建步骤
1. 定义Runnable接口的实现类,重写run()方法,该方法为线程执行体
2. 创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
3. 启动线程,通过调用线程对象的start()方法来启动线程
Runnable创建代码
 package concurrent;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @Description: 线程创建
* @Author: lizhouwei
* @CreateDate: 2018/5/20 16:17
* @Modify by:
* @ModifyDate:
*/
class MyRunnable implements Runnable {
private AtomicInteger ticket = new AtomicInteger(10); public void run() {
for (int i = 1; i <= ticket.intValue(); i++) {
System.out.println(Thread.currentThread().getName() + " ticket " + i);
}
}
} public class RunnableDmo {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
myThread.start();
}
}

4. start() 和 run()的区别

start():启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用(会抛出异常)。
run() :run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!

2. start() 源码(by jdk1.8)

public synchronized void start() {

         //判断状态是否为 New ;
if (threadStatus != 0)
throw new IllegalThreadStateException(); // 将线程添加到ThreadGroup中
group.add(this); boolean started = false;
try {
// 通过start0()启动线程
start0();
// 设置started标记
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}

5. 通过Thread的实例对象调用start()方法到底是怎么启动线程的?下面对其实现方式做一些简单的补充。

  1. 基于Kernel Thread(KLT)的映射来实现:KLT是内核线程,内核线程由OS直接完成调度切换,它相对应用程序的线程来讲只是一个接口,外部程序会使用一种轻量级进程(Light Weight Process,LWP)来与KLT进行一对一的接口调用。也就是说,进程内部会尝试利用OS的内核线程去参与实际的调度,而自己使用API调用作为中间桥梁与自己的程序进行交互。
  2. 基于用户线程(User Thread,UT)的实现:这种方式是考虑是否可以没有中间这一层映射,自己的线程直接由CPU来调度,或许理论上效率会更高。不过这样实现时,用户进程所需要关注的抽象层次会更低一些,跳过OS更加接近CPU,即自己要去做许多OS做的事情,自然的OS的调度算法、创建、销毁、上下文切换、挂起等都要自己来搞定(因为CPU只做计算)。这样做显然很麻烦,许多人曾经尝试过,后来放弃了。
  3. 混合实现方式:它的设计理念是希望保留Kernel线程原有架构,又想使用用户线程,轻量级进程依然与Kernel线程一一对应保持不变,唯一变化的就是轻量级进程不再与进程直接挂钩,而是与用户线程挂钩,用户线程并不一定必须与轻量级进程一一对应,而是多对多,就像在使用一个轻量级进程列表一样,这样增加了一层来解除轻量级进程与原进程之间的耦合,可能会使得调度更为灵活。

在以前的JDK版本中,尝试使用UT的方式来实现,但后来放弃了,采用了与Kernel线程对应的方式,至于一些细节,与具体的平台有很大的关系,JVM会适当考虑具体平台的因素去实现,在JVM规范中也没规定过必须如何去实现,所以对于程序员来讲,只需要知道在new Thread(),调用start()方法后,理论上就有一个可以被OS调度的线程了。

Java多线程系列 基础篇02 线程的创建和运行的更多相关文章

  1. Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式

    概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...

  2. Java多线程系列 基础篇01 线程的状态

    1.进程和线程 进程: 计算机中程序关于某数据集合的一次运行活动,是计算机系统进行资源分配和调度的基本单位,是操作系统结构的基础. 线程: 线程是进程的实例,是CPU进行资源分配和调度的最小单位,线程 ...

  3. Java多线程系列 基础篇03 线程的优先级和守护线程

    1. 线程优先级 现代操作系统中基本上使用时间分片的方式调度线程,通过设置线程优先级,使优先级高的线程获得时间片的次数多于优先级低的线程. 在java 线程中,通过一个整形变量prority来控制优先 ...

  4. Java多线程系列 基础篇04 线程中断

    1. 中断线程 中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程进行了中断操作,其他线程通过调用该线程的interrupt()方法对其进行中断操作,线程通过检查自身是否被中断来 ...

  5. Java多线程系列--“基础篇”05之 线程等待与唤醒

    概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...

  6. Java多线程系列--“基础篇”06之 线程让步

    概要 本章,会对Thread中的线程让步方法yield()进行介绍.涉及到的内容包括:1. yield()介绍2. yield()示例3. yield() 与 wait()的比较 转载请注明出处:ht ...

  7. Java多线程系列--“基础篇”07之 线程休眠

    概要 本章,会对Thread中sleep()方法进行介绍.涉及到的内容包括:1. sleep()介绍2. sleep()示例3. sleep() 与 wait()的比较 转载请注明出处:http:// ...

  8. Java多线程系列--“基础篇”09之 interrupt()和线程终止方式

    概要 本章,会对线程的interrupt()中断和终止方式进行介绍.涉及到的内容包括:1. interrupt()说明2. 终止线程的方式2.1 终止处于“阻塞状态”的线程2.2 终止处于“运行状态” ...

  9. Java多线程系列--“基础篇”10之 线程优先级和守护线程

    概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...

随机推荐

  1. python局部变量与全局变量

    name = "head first python"def what_happens_here():    print(name)  1    name = "pytho ...

  2. vue2.0中怎么获取元素

    在元素上添加 v-el:food-wrapper (不用驼峰的写法) vue1版本 报错: vue2版本 (vue2把vue1中的 v-el 改为了 ref vue1 v-el:foods-wrapp ...

  3. linux 下 ifcfg-eth0 配置 以及ifconfig、ifup、ifdown区别

    这3个命令的用途都是启动网络接口,不过,ifup与ifdown仅就 /etc/sysconfig/network- scripts内的ifcfg-ethx(x为数字)进行启动或关闭的操作,并不能直接修 ...

  4. Netty通过心跳保持长链接

    Netty自带心跳检测功能,IdleStateHandler,客户端在写空闲时主动发起心跳请求,服务器接受到心跳请求后给出一个心跳响应.当客户端在一定时间范围内不能够给出响应则断开链接. public ...

  5. mysql使用mysqldump 与 mysqlimport进行数据库迁移

    1.导入数据库 1)source source /home/platvt/product/pc2_create_tables.sql 2)mysqlimport 使用mysqlimport导入数据: ...

  6. 一知半见的load与get

    http://www.oschina.net/question/5189_3991 我只用get.load不管.

  7. vue Object.freeze() 优化

    参考自:https://segmentfault.com/a/1190000006191558 Object.freeze()是ES5新增的特性,可以冻结一个对象,防止对象被修改. vue 1.0.1 ...

  8. SQL Server排序的时候使null值排在最后

    首先建一个表插入一些测试数据 create table UserInfo ( UserInfoID        int not null identity(1,1) primary key, Use ...

  9. vim  模式查找

    1. / 正向查找, ?反向查找 2. \v 激活very magic搜索模式,撰写正则表达式更接近于perl的正则表达式,大多数字符不需要进行转义 3. \V 激活noVeryMagic模式,按字符 ...

  10. mac 升级系统后 ”任何来源“被取消了找回方法

    找回方法 终端输入: sudo spctl --master-disable