创建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 ...
随机推荐
- 【Maven】 Eclipse使用Maven创建Java Web 项目(一)
需求:创建一个Servlet版本3.0,Java版本是1.7的Maven Web项目 创建环境: 系统:window 7 软件:Eclipse.Maven 创建步骤: 1.使用eclipse工具创建m ...
- day04流程控制,if分支结构,while,for循环
复习 ''' 1.变量名命名规范 -- 1.只能由数字.字母 及 _ 组成 -- 2.不能以数字开头 -- 3.不能与系统关键字重名 -- 4._开头有特殊含义 -- 5.__开头__结尾的变量,魔法 ...
- AjaxPro对象参数传递
1.客户端配置 2.服务端注册,配置 对象参数用到的方法 3.Web.config文件配置 需要注意的是ajax以及ajaxpro调用的方法必须是静态方法,如果存在非静态方法可以从页面作为参数传递
- (转载)C#关于DateTime得到的当前时间的格式和用法
今天看到工程里有关DateTime的有关知识,之前了解一些用法,比如怎么获取年月日,当前系统时间等等,但是,感觉还是有好多不知道,于是上网搜罗了一下,找到很多有关知识,现在与大家分享下: Date ...
- 【shell脚本】 变量基础学习整理
1.linux系统环境 echo 'echo /etc/profile ' >> /etc/profile echo 'echo /etc/bashrc' >> /etc/ba ...
- SQLLITE HELPER
using System;using System.Data.SQLite; namespace SQLiteSamples{ class Program { //数据库连接 ...
- 机器学习之决策树_CART算法
目录 3.CART算法(classification and regression tree tree) 3.1 CART生成算法(回归树生成和分类树生成) 3.2 CART剪枝 决策树基本知识参考, ...
- 『OpenCV3』基于色彩分割图片
一.遍历图像实现色彩掩码 本节我们实现这样一个算法,我们指定某种颜色和一个阈值,根据输入图片生成一张掩码,标记符合的像素(和指定颜色的差异在阈值容忍内). 源代码如下,我们使用一个class完成这个目 ...
- 2015-10-21 C#1
C#(一) 一.C#的数值类型 byte----字节型 short---短整型 int------整型 long----长整型 char----字符型 float----单精度型 double--双精 ...
- learning makefile manner of working