创建Java多线程的两种方式和线程异常
一.使用多线程的两种方法
使用多线程的两种方法有:继承Thread类和实现runable接口。
二.继承Thread类
来看一下thread类的源代码:
class Thread implements Runnable {
首先可以看出thread类也是实现Runable接口的run方法如下:
public void run() {
if (target != null) {
target.run();
}
}
下面就是一个创建继承Thread的类的列子:
public class ExThreadText extends Thread {
@Override
public void run(){
for(int i=0;i<20;i++){
System.out.println("我自己创建的线程");
}
}
public static void main(String[] args) {
new ExThreadText().start();
System.out.println("程序结束!");
}
}
结果如下
首先我们需要明白在这个程序里面有多少个线程?应该是两个线程一个是main方法的线程一个是我run方法里面的一个线程
从结果可以看出这两个线程的调用和创建的顺序是无关的,
在这个代码实例里面我们重写了run方法,并使用start方法来调用,那为什么不用run方法来调用呢?我们来看看run方法调用会有什么结果:
可以看出现在的两个"线程"已经是按照顺序执行的了,其实现在并不是多线程,就是一个单线程按照流程来执行。
总结:1.多线程的调用是无序的
2.多线程需要使用start方法来调用而不是run方法,同样start方法来调用线程也是无序的
三.使用runable接口来实现多线程
由于Java不提供多继承,所以当我们继承了Thread类的时候我们就不能继承其它的父类了,为了解决这一个问题,我建议实现runable接口。
首先继承runable接口必须重写他的run方法,代码如下:
public class ImRunableText implements Runnable {
@Override
public void run(){
//重写run方法
}
}
那怎么使用这个runable接口的子类呢?
我们来看看Thread类的构造方法:

可以看出Thread类的构造器可以接受实现Runable接口的子类对象(不要忘了thread类也是实现runable接口的),同时他还重载了一个构造器可以为线程命名。
那么我们就可以使用这个runable的实现子类了,代码如下:
public class ImRunableText implements Runnable {
@Override
public void run(){
//重写run方法
for(int i=0;i<10;i++){
System.out.println("run方法");
}
}
public static void main(String[] args) {
Thread thread =new Thread(new ImRunableText(),"线程");
thread.start();
System.out.println("结束了");
}
}
结果如下:
四.线程中的数据共享和线程安全
4.1数据不共享
数据不共享那就是一个线程一个数据,单独执行互不影响。代码如下:
这是一个线程类,他有自己的字段num为10。
public class DataNShare extends Thread{
private int num =10;
private String name;
public DataNShare(String name){
this.name=name;
}
@Override
public void run(){
for(;num>0;){
System.out.println("当前线程为:"+name);
System.out.println("num值为"+num);
num--;
}
}
}
在设置一个测试类,创建三个对象,各自进行测试代码如下:
public class Text {
public static void main(String[] args) {
DataNShare d1=new DataNShare("线程1");
DataNShare d2=new DataNShare("线程2");
DataNShare d3=new DataNShare("线程3");
d1.start();
d2.start();
d3.start();
}
}
测试结果:
可以看出一开始是没有问题的,但是在后面出现了乱序的情况。
那么出现了乱序的情况是不是就一定证明了程序出错了呢?
我们来改进一下这个DataNShare类中的Run方法
public void run(){
for(int i =1;num>=0;i++){
System.out.println("当前线程为:"+name);
System.out.println("num值为"+num);
num--;
if(num==0){
System.out.println("*************i的值为"+i+"*************");
}
}
}
那么也就是说当我的i值输出每一次输出10那么就是代表每一条线程都是执行互不影响的。
*3,虽然还是存在乱序的情况,但是至少保证我们的每一条线程执行都是10次没有问题的。那么出现乱序的情况就是输出语句的问题。
4.2数据共享
数据共享就是多个线程可以访问一个数据,代码如下:
放有共享数据的线程类:
public class DataShare extends Thread {
private int num=3;//共享数据
@Override
public void run(){
num--;//共享数据减一
System.out.println("当前线程为:"+this.currentThread().getName()+"num值为:"+num);
}
}
处理类:
public class Text {
public static void main(String[] args) {
//将共享数据放入3个线程里进行处理
DataShare d=new DataShare();
Thread t1=new Thread(d,"t1");
Thread t2=new Thread(d,"t2");
Thread t3=new Thread(d,"t3");
t1.start();
t2.start();
t3.start();
}
}
结果如下:
在这里出现的这种情况就是线程不安全状态。那么怎么解决这个问题呢?
使用关键字synchronized(同步化的)来解决。
当一个方法使用该关键字那么在多个线程执行这个方法时,每一个线程获得执行该方法的执行权就会把这个方法上锁结束后开锁,只有等到这个方法没有被上锁时才可以被其他线程运行。
看看改进后的代码:
public class DataShare extends Thread {
private int num=3;//共享数据
@Override
synchronized public void run(){
num--;//共享数据减一
System.out.println("当前线程为:"+this.currentThread().getName()+"num值为:"+num);
}
}
结果:
总结:当多个线程在共享一个数据时,可能会造成线程异常,应该使用关键字synchronized来实现同步化,在后面还会深入了解同步化。
创建Java多线程的两种方式和线程异常的更多相关文章
- 阿里巴巴--java多线程的两种实现方式,以及二者的区别
阿里巴巴面试的时候,昨天问了我java面试的时候实现java多线程的两种方式,以及二者的区别当时只回答了实现线程的两种方式,但是没有回答上二者的区别: java实现多线程有两种方式: 1.继承Thre ...
- Java实现多线程的两种方式
实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...
- Java多线程的两种实现方式
Java总共有两种方式实现多线程 方式1:通过继承Thread类的方式 package com.day04; /** * 通过继承Thread类并复写run方法来是实现多线程 * * @author ...
- Java中实现多线程的两种方式之间的区别
Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...
- java多线程系类:基础篇:02常用的实现多线程的两种方式
本章,我们学习"常用的实现多线程的2种方式":Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多 ...
- 【Java多线程】两种基本实现框架
Java多线程学习1——两种基本实现框架 一.前言 当一个Java程序启动的时候,一个线程就立刻启动,改程序通常也被我们称作程序的主线程.其他所有的子线程都是由主线程产生的.主线程是程序开始就执行的, ...
- 【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式
1.Java多线程的概念 同一时间段内,位于同一处理器上多个已开启但未执行完毕的线程叫做多线程.他们通过轮寻获得CPU处理时间,从而在宏观上构成一种同时在执行的假象,实质上在任意时刻只有一个线程获得C ...
- 一步步分析Java深拷贝的两种方式-clone和序列化
今天遇到一道面试题,询问深拷贝的两种方法.主要就是clone方法和序列化方法.今天就来分析一下这两种方式如何实现深拷贝.如果想跳过解析的朋友,直奔"重点来了!"寻找答案. clon ...
随机推荐
- Docker Kubernetes Service 网络服务代理模式详解
Docker Kubernetes Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...
- IP白名单的实现(PHP)
有些项目可能会用到一个IP地址的白名单黑名单之类的验证. 比如,只有IP地址在白名单中,才可以访问该系统. 那么此时,白名单的维护,一般是一个文件,里边是一些IP地址(每行一个IP),当然也有的可能是 ...
- Python将list中的string批量转化成int/float
data = ['] data = map(eval, data) print data 输出:[1, 3.2, 2] 但是在Python3下我们输入: ls=[1,2,3] rs=map(str,l ...
- linux基础之用户和组管理及权限
一.用户和组管理 相关配置文件 /etc/passwd: 用户名 : 密码占位符 : UID : GID : COMMENTS : 家目录 :默认shell /etc/group: 组名 : 组密码占 ...
- spring初体验 一之helloworld
今天开始学习spring,每天都会将自己学习的一些内容,或是一些总结以博客的形式记录下来,方便自己以后回顾,如果能给他人学习带来丁点的帮助那也是最好不过了.本系列博文的spring学习是基于4.0版本 ...
- HDU 6186 CS Course(前缀+后缀)
http://acm.hdu.edu.cn/showproblem.php?pid=6186 题意:给出n个数,共有n次询问,每次询问给出一个数p,求除去第p个数后的n-1个数的&.|.^值. ...
- 安装Go插件遇到的问题及解决方法
1. 问题:在 Windows 平台下使用 go get 安装sqlite3 驱动时报错 The remote end hung up unexpectedly ? 原因及解决方法: 原因可能有两种: ...
- guxh的python笔记十:包和模块
1,包和模块 包package:本质就是一个文件夹/目录,必须带一个__init.__.py的文件 模块module:.py结尾的python文件 2,导入方法 import pandas, coll ...
- Android中如何解决editText一进入activity就自动获取焦点的bug
有时候我们在进入activity 的时候,EditText会自动聚焦 有人说搞个宽高 都为0dp的EditText 但是我们搞代码的肯定要从实际层面解决,这样更能说服人 所以只需要在EditText的 ...
- 理解SQL的左连接与右连接
假设有A,B两个表. 表A记录如下: aID aNum 1 a20050111 2 a20050112 3 a20050113 4 a20050114 5 a20050115 表B记录如下: bID ...