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

 使用多线程的两种方法有:继承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. servlet登录界面进行用户名和密码验证

    一.建立LoginServlet项目并建立如下目录 二.在Login.html中编写登录界面代码 三.在css文件中新建login.css文件 四.在src文件中添加LoginServlet.java ...

  2. react-router 4.0(二)传参

    import React from 'react'; import ReactDOM from 'react-dom' import {Link,Route,HashRouter} from 'rea ...

  3. Spring Boot 2集成Redis

    Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.redis是一个key-value存储系统,支持存储的valu ...

  4. P4512 【模板】多项式除法

    思路 多项式除法板子 多项式除法 给出\(A(x)\)和\(B(x)\),求一个\(n-m\)次的多项式\(D(x)\),一个\(m-1\)次多项式\(R(x)\),满足 \[ A(x)=B(x)D( ...

  5. Unity3D_UGUI判断鼠标或者手指是否点击在UI上

    比如战斗场景,UI和3D场景同时都需要响应触摸事件,如果同时响应可能就会出现触摸UI的时候影响到了3D部分.为了解决这个问题在判断3D响应之前要先判断手指是否点击在UI上. 以前NGUI的时候都是自己 ...

  6. TCP协议三次握手、四次挥手

    TCP的概述 TCP 把连接作为最基本的对象,每一条 TCP 连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到 IP 地址即构成了套接字,例如,若 IP 地址为 192 ...

  7. Linux文件结构

    /: 根目录,所有的目录.文件.设备都在/之下,/就是Linux文件系统的组织者,也是最上级的领导者. /bin: bin 就是二进制(binary)英文缩写.在一般的系统当中,都可以在这个目录下找到 ...

  8. 理解SSL、HTTPS原理中的对称加密与非对称加密

    1.对称性加密 双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密. 简单来说就是:加密与解密都是同一个秘钥.   优点:通常在消息发送方需要加密大量数据时使用,算 ...

  9. kafka.common.FailedToSendMessageException: Failed to send messages after 3 tries. 最无语的配置

    注意: 本文不谈废话,低级问题请自行检查. 我使用Java版本的Kafka Producer生产数据,但是抛出了这个异常.百思不得其解,明明防火墙配置,ZooKeeper,Kafka配置都是没问题的啊 ...

  10. laravel框架中的邮箱发送

    1.设置邮件服务器登录 163邮箱设置 POP3/SMTP/IMAP勾选:POP3/SMTP服务 IMAP/SMTP服务 保存 设置客户端授权密码 2.在laravel中配置服务器 打开.env文件 ...