Java中线程的实现
在Java中要想实现多线程代码有两种方法,一种是继承 Thread 类,另一种就是实现 Runnable 接口
一、继承 Thread 类
Thread 类是在 java.lang 包中定义的,一个类只要继承了 Thread 类,此类就称为多线程操作类。
在 Thread 子类中,必须明确地覆写 Thread 类中的 run() 方法,此方法为线程的主体
例子:继承Thread类实现多线程
class MyThread extends Thread { //继承Thread类
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { //覆写Thread类中的run 方法
for(int i=0;i<5;i++){
System.out.println(name + " 运行:i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.run();
mt2.run();
}
}
程序运行结果
线程A 运行:i = 0
线程A 运行:i = 1
线程A 运行:i = 2
线程A 运行:i = 3
线程A 运行:i = 4
线程B 运行:i = 0
线程B 运行:i = 1
线程B 运行:i = 2
线程B 运行:i = 3
线程B 运行:i = 4
发现以上的程序是先执行完mt1对象之后再执行mt2对象,并没有交错运行,也就是说,此时线程实际上并没有被启动,
还是属于顺序式的执行方式,那么该如何启动线程呢?如果要正确地启动线程,是不能直接调用run()方法的,而应该
是调用从 Thread 类中继承而来的 start() 方法,具体代码如下:
例子:启动线程
class MyThread extends Thread { //继承Thread类
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { //覆写Thread类中的run 方法
for(int i=0;i<5;i++){
System.out.println(name + " 运行:i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.start(); //启动多线程
mt2.start();
}
}
程序运行结果(可能的一种结果)
线程A 运行:i = 0
线程B 运行:i = 0
线程A 运行:i = 1
线程B 运行:i = 1
线程A 运行:i = 2
线程B 运行:i = 2
线程A 运行:i = 3
线程B 运行:i = 3
线程A 运行:i = 4
线程B 运行:i = 4
从程序的运行结果中可以发现,两个线程现在是交错运行的,哪个线程对象抢到了CPU资源,哪个线程就可以运行,
所以程序每次的运行结果是不一样的,在线程启动时虽然调用的是start()方法,但实际上调用的却是run()方法的主体
二、实现 Runnable 接口
在Java中也可以通过实现 Runnable 接口的方式实现多线程,Runnable 接口中只定义了一个抽象方法: public void run();
例子:实现Runnable接口
class MyThread implements Runnable { //实现Runnable接口
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { //覆写Runnable类中的run 方法
for(int i=0;i<5;i++){
System.out.println(name + " 运行:i = " + i);
}
}
}
以上代码通过实现Runnable接口实现多线程,从之前代码中可以知道,要想启动一个多线程必须要使用start()方法完成
如果继承了Thread类,则可以直接从Thread类中使用start()方法 但是现在实现的是Runnable接口,该如何启动多线程呢?
实际上,此时还是要依靠Thread类完成启动,在Thread类中提供了
public Thread(Runnable target) 和 public Thread(Runnable target,String name) 两个构造方法
这两个构造方法都可以接收Runnable的子类实例对象,所以就可以依靠此点启动多线程
例子:使用Thread类启动多线程
class MyThread implements Runnable { //实现Runnable接口
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { //覆写Runnable类中的run 方法
for(int i=0;i<5;i++){
System.out.println(name + " 运行:i = " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A"); //实例化Runnable子类对象
MyThread mt2 = new MyThread("线程B");
Thread t1 = new Thread(mt1); //实例化Thread类对象
Thread t2 = new Thread(mt2);
t1.start(); //启动线程
t2.start();
}
}
程序运行结果
线程B 运行:i = 0
线程A 运行:i = 0
线程B 运行:i = 1
线程A 运行:i = 1
线程B 运行:i = 2
线程B 运行:i = 3
线程A 运行:i = 2
线程B 运行:i = 4
线程A 运行:i = 3
线程A 运行:i = 4
从以上两种实现可以发现,无论使用哪种方式,最终都必须依靠Thread类才能启动多线程
三、Thread类和Runnable接口
通过Thread类和Runnable接口都可以实现多线程,那两者有哪些联系和区别呢,下面观察Thread类的定义
public class Thread extends Object implements Runnable
从Thread类的定义可以发现,Thread类也是Runnable接口的子类。实际上Thread类和Runnable接口之间在使用上也是
有区别的,如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,就可以方便地实现资源的共享。
例子:继承Thread类不能资源共享
class MyThread extends Thread { // 继承Thread类
private int ticket = 5; //一共5张票
public void run() { // 覆写run 方法
for (int i = 0; i < 100; i++) {
if(ticket > 0){ //判断是否有剩余票
System.out.println("卖票:ticket = " + ticket--);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
mt1.start(); //启动线程
mt2.start();
mt3.start();
}
}
程序运行结果
卖票:ticket = 5
卖票:ticket = 5
卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 4
卖票:ticket = 2
卖票:ticket = 3
卖票:ticket = 1
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 2
卖票:ticket = 1
卖票:ticket = 1
以上程序通过Thread类实现多线程,程序中启动了三个线程,但三个线程却分别卖了各自的5张票,
并没有达到资源共享的目的。
例子:实现Runnable接口可以实现资源共享
class MyThread implements Runnable { // 实现Runnable接口
private int ticket = 5; //一共5张票
public void run() { // 覆写run 方法
for (int i = 0; i < 100; i++) {
if(ticket > 0){ //判断是否有剩余票
System.out.println("卖票:ticket = " + ticket--);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt).start(); //启动线程
new Thread(mt).start();
new Thread(mt).start();
}
}
程序运行结果
卖票:ticket = 5
卖票:ticket = 3
卖票:ticket = 4
卖票:ticket = 1
卖票:ticket = 2
从程序的运行结果中可以发现,虽然启动了3个线程,但是3个线程一共才卖了5张票,即ticket属性被所有的线程对象共享
可见,实现 Runnable 接口相对于继承Thread类来说,有如下显著的优势:
适合多个相同程序代码的线程去处理同一资源的情况。
可以避免由于Java的单继承特性带来的局限
增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
所以,在开发中建议使用 Runnable 接口实现多线程
作者:itmyhome
Java中线程的实现的更多相关文章
- java中线程分两种,守护线程和用户线程。
java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...
- java中线程机制
java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...
- Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞
Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...
- Java中线程的实现:
Java中线程的实现: 一.线程简介: 实现的两种方式为: 1.Thread类 2.Runnable接口 都在java.lang中 都有共通的方法:public void run() 二.线程常用方法 ...
- JAVA中线程同步方法
JAVA中线程同步方法 1 wait方法: 该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所 ...
- 多线程(三) java中线程的简单使用
java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...
- Java中线程池,你真的会用吗?
在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...
- Java中线程同步的理解 - 其实应该叫做Java线程排队
Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...
- 沉淀再出发:java中线程池解析
沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...
- Java中线程和线程池
Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...
随机推荐
- js中一切都是对象
<script> function cat(){} var cat = new cat(); console.log(cat.constructor) console.log(typeof ...
- J: Just for fun
J: Just for fun 时间限制: 1 s 内存限制: 128 MB 题目描述 最近carryon在准备考研复习高数,复习到微分学的时候看到一个求曲面某点的切平面的问题 ...
- flutter dup get
有很多 flutter library 中有两种导入方式 with dup: dup get 这种导入方式是需要依赖于 Dart SDK 下载 Dart SDK 地址:http://www.gekor ...
- Linux I2C驱动--用户态驱动简单示例
1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0 2. I ...
- V1-bug Alpha阶段测试报告
发现的Bug Bug现象 Bug原因 是否解决 访问到错误的视图 路由正则写的太过宽泛 是 主题太长时超过页面宽度,导致超过顶部的宽度 / 否 无法使用域名访问服务器 后端没有在配置文件的ALLOWE ...
- 本科生毕业论文->计算机类(1)
写在前面:作为一个计算机类学生,本文只是面向计算机类本科论文进行了一些小经验总结,每个学校的论文要求不一致,具体的参考规范可以看学校的通知,毕业论文作为毕业的一个重要审核标准,写好毕业论文是非常重要的 ...
- 推荐-Everything搜索工具
简介: windows操作系统下极其强大的文件搜索工具. 下载: https://www.voidtools.com/downloads/ 推荐理由: 速度之快难以想象,日常工作必备工具之一. 发现的 ...
- web测试工具总结
纯粹的手工测试早已不满足如今的项目需求,各种测试工具的应用早已成为普遍趋势.如何选取合适的工具来完成对应的测试工作?本文将针对Web测试,列举 一些推荐的测试工具,并加以简单介绍. (每个工具的实际 ...
- 已有插件支持requirejs
define(["jquery"], // Require jquery function($){ //把你原来的插件代码放这里吧,这样就行了 //注意文件命名 }) ...
- 【lua】LWT request请求处理
request请求处理 通过mod_lwt模块提供的处理程序来调用Lua脚本处理HTTP请求.具体流程: 判断该请求是否由LWT处理,如果不是,拒绝处理请求; 判断Lua脚本文件是否存在,如果不存在, ...