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

 使用多线程的两种方法有:继承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. Weighted Quick Union with Path Compression (WQUPC)

    在WQU基础上,添加一步路径压缩. 前面的优化都是在union,路径压缩是在find上面做文章. 这里的路径压缩我还没完全搞明白,之后不断再来的,不管是理解还是博文编排素材之类的. 说是加一步压缩是确 ...

  2. 【题解】Luogu P4324 [JSOI2016]扭动的回文串

    原题传送门 这题实际挺水的 先对两个字符串分别跑马拉车 就能求出1.2类扭动回文串最大的长度 考虑第三类的扭动回文串\(S(i,j,k)\),一定可以表示为\(A(i,l)+A(l+1,j)+B(j, ...

  3. python from entry to abandon

    学习Linux已经有大致两周了,依然感觉到自己仍然在运维的大门外徘徊.于是我想要找到一个在Linux之外的业余方向,可以以作为枯燥基础学习的调节.没过多久我就发现了Python可以说是钦定的选择,它作 ...

  4. JS打开新窗口防止被浏览器阻止的方法

    这篇文章主要介绍了JS打开新窗口防止被浏览器阻止的方法,分析对比了常用方法与改进方法,是非常实用的技巧,需要的朋友可以参考下 本文实例讲述了JS打开新窗口防止被浏览器阻止的方法.分享给大家供大家参考. ...

  5. Family 科

    拉丁语 familia 目--> 总科-->科-->亚科(亚科的拉丁文分类滋味通常是-inae) [族] 属

  6. 基于Bootsrap的BeyondAdmin前端模板 --分享

    1.PC端 2.移动端 3.下载 最新:http://www.yidt.cn/ 链接:https://pan.baidu.com/s/1Tx6EVmGFnVV7H7h3SFwldA 提取码:0btw

  7. 在ionic中使用短信验证码倒计时

    页面上 <button class="code" (click)="getCode()" [disabled]="!verifyCode.dis ...

  8. 『Python』VS2015编译源码注意事项

    一.2.5.6版本源码编译 解压 Python-2.5.6.tgz 进入 Pcbuild8 文件夹,使用 vs 2013 打开 pybuild.sln (vs 解决方案),进入 vs2015IDE 环 ...

  9. Matlab:显(隐)式Euler和Richardson外推法变步长求解刚性问题

    一.显示Euler 函数文件:Euler.m function f=Euler(h,Y) f(1,1)=Y(1)+h*(0.01-(1+(Y(1)+1000)*(Y(1)+1))*(0.01+Y(1) ...

  10. AIX中PV,VG,LV及FS常用相关命令

    1.PV常用相关命令 1)lsdev:列出ODM(Object Data Manager)中的设备. 2)chdev:修改一个AIX设备的属性. 3)mkdev:创建一个AIX设备. 4)chpv:修 ...