一.使用多线程的两种方法

 使用多线程的两种方法有:继承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多线程的两种方式和线程异常的更多相关文章

  1. 阿里巴巴--java多线程的两种实现方式,以及二者的区别

    阿里巴巴面试的时候,昨天问了我java面试的时候实现java多线程的两种方式,以及二者的区别当时只回答了实现线程的两种方式,但是没有回答上二者的区别: java实现多线程有两种方式: 1.继承Thre ...

  2. Java实现多线程的两种方式

    实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...

  3. Java多线程的两种实现方式

    Java总共有两种方式实现多线程 方式1:通过继承Thread类的方式 package com.day04; /** * 通过继承Thread类并复写run方法来是实现多线程 * * @author ...

  4. Java中实现多线程的两种方式之间的区别

    Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...

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

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

  6. java多线程系类:基础篇:02常用的实现多线程的两种方式

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

  7. 【Java多线程】两种基本实现框架

    Java多线程学习1——两种基本实现框架 一.前言 当一个Java程序启动的时候,一个线程就立刻启动,改程序通常也被我们称作程序的主线程.其他所有的子线程都是由主线程产生的.主线程是程序开始就执行的, ...

  8. 【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式

    1.Java多线程的概念 同一时间段内,位于同一处理器上多个已开启但未执行完毕的线程叫做多线程.他们通过轮寻获得CPU处理时间,从而在宏观上构成一种同时在执行的假象,实质上在任意时刻只有一个线程获得C ...

  9. 一步步分析Java深拷贝的两种方式-clone和序列化

    今天遇到一道面试题,询问深拷贝的两种方法.主要就是clone方法和序列化方法.今天就来分析一下这两种方式如何实现深拷贝.如果想跳过解析的朋友,直奔"重点来了!"寻找答案. clon ...

随机推荐

  1. Linux 查看系统状态

    查看系统状态 命令:vmstat 命令:vmsta 1 10               #每1秒钟1次显示10次. r:几个进程在占用cpu b:等待IO值 Swpd:多少交换内存 free:剩余内 ...

  2. 无实体反序列化Json

    public class ExectendHelp { private int index = 0; public void GetLast(JObject obj, ref JToken token ...

  3. Delphi10.2 Tokyo试用(1)

    最近下载了Delphi10.2 Tokyo,试用了一下,感觉不错,尤其是针对Linux的开发,总算出来了,可以考虑把原来服务器重新编译成RedHat上使用了,免得客户一天到晚喊Windows不安全,要 ...

  4. _mount_allowed

    该表配置可以坐骑的使用区域,可能需要修改spell.dbc,允许在室内等特殊区域使用坐骑技能

  5. 随机森林和GBDT

    1. 随机森林 Random Forest(随机森林)是Bagging的扩展变体,它在以决策树 为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机特征选择,因此可以概括RF ...

  6. VS 2017常用快捷键

    VS 2017常用快捷键 1.查找和替换 1)查找:使用组合键“Ctrl+F”: 2)替换:使用组合键“Ctrl+H”. (批量更改函数名的神器!) 2.复制/剪切/删除整行代码 1)如果你想复制一整 ...

  7. javascript里文字选中/选中文字

    一.获取/清除选中的文字 //获取选中的文字 document.getElementById("get").onclick = function () { var txt = wi ...

  8. http content-type 与 java后端处理

    http中的常用的content-type有: application/x-www-form-urlencoded;charset=UTF-8  传递表单类数据 application/json;ch ...

  9. composer修改成国内镜像

    因为composer安装包数据是从github.com上下载的,安装包的元数据从packagist.org上下载 作为两个国外的网站,连接速度会很慢,而且很有可能网站被墙. 所以composer中国全 ...

  10. 从rnn到lstm,再到seq2seq(二)

    从图上可以看出来,decode的过程其实都是从encode的最后一个隐层开始的,如果encode输入过长的话,会丢失很多信息,所以设计了attation机制. attation机制的decode的过程 ...