`
Strive_sprint
  • 浏览: 21666 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

java多线程初步理解

 
阅读更多

 

      也许我们经常做的事就是一边聊QQ一边听音乐,有的还一边玩游戏,这一切都是多任务实现的。而java语言使用多线程实现了一个程序中的多个任务同时运行。

      那到底是不是同时执行多线程呢?显然不是,CPU一次只能然一个线程执行,由于线程之间切换速度很快,所以在我们看来是同时执行的。

 

java中如何实现多线程:

      1.继承Thread类创建多线程。

      2.实现Runnable接口创建多线程。

 

      继承Thread类,重写run()方法是实现多线程的方式之一,Thread类本身就实现了Runnable接口。

如下例继承Thread类:

public class ThreadTest extends Thread{
	public void run(){
		while(true){
			String name = Thread.currentThread().getName();
			sayHello(name);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void sayHello(String name){
		System.out.println(name+"说hello");
	}
	public static void main(String [] agrs){
		ThreadTest tt1 = new ThreadTest();
		ThreadTest tt2 = new ThreadTest();
		tt1.start();
		tt2.start();
	}
}

 

我的运行结果(每个人的运行结果都会不同):

Thread-0说hello
Thread-1说hello
Thread-1说hello
Thread-0说hello
Thread-1说hello
Thread-0说hello
Thread-1说hello
Thread-0说hello

 

      可以看出线程是一个一个执行的,并且不是按顺序执行的,红色标记的地方说明。cpu为每个线程分配了时间片,哪个线程得到了CPU,哪个线程就得到执行,这个在后面再说明。

 

      实现Runnable接口,实现run()方法来创建多线程,如下例:

public class ThreadTest implements Runnable{
	public void run() {
		while(true){
			String name = Thread.currentThread().getName();
			sayHello(name);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void sayHello(String name){
		System.out.println(name+"说hello");
	}
	public static void main(String [] agrs){
		Runnable r = new ThreadTest();
		Thread thread1 = new Thread(r);
		Thread thread2 = new Thread(r);
		thread1.start();
		thread2.start();
	}
}

      这里只是创建线程对象有稍微的区别。

 

      那么他们之间有什么区别?甚至有的人问哪个更好?因为我就这么问过,但是在网上找到的答案基本都很片面,只找到了一个说的比较好,还需要时间研究研究。我列出来大家看看:

      1.适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。

      2.可以避免由于java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。

      3.有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例

 

      那么实现多线程都是对run()方法重写,为什么不是直接调用run()方法而是调用start()方法呢?这里我们来看看run()和start()方法的区别。

start():

      通过调用start()方法来启动线程,此时线程处于就绪状态,一旦得到CPU时间片就执行run()方法,方法run()称为线程体,它包含了要执行这个线程的内容,当run()方法运行结束,线程随即终止。

run():

      run()方法只是Thread类的一个普通方法,如果直接调用run()方法,程序中只有主线程这一个线程,执行路径只有一条,要这个方法执行完才能执行下面的代码,这就没达到多线程的目的。

 

继续看如上例子,如果是:

      thread1.run();
         thread2.run();

那么运行结果为:

main说hello
main说hello
main说hello
main说hello
main说hello
main说hello
main说hello

 

      main就是我们一直以来接触的程序的入口(主方法),其实它本身就是一个线程,并且是主线程。 

 

线程的生命周期

      线程具有生命周期,包含3个状态,使用线程实例调用start()方法之前,线程处于出生状态,当调用start()方法后,线程就处于就绪状态,当线程得到系统资源后进入运行状态,当时间片结束线程又回到就绪状态,继续等待资源。

 

      而在线程执行过程中,线程又可能转入等待,睡眠,阻塞或者死亡状态

 

      1.线程在执行过程中调用wait()方法进入等待状态,这时线程释放持有的资源,必须采用notify()或者notifyAll()方法来唤醒该进程或者被别的对象调用interrupt()方法打断,这个方法会抛出一个InterruptedException异常,这个异常如果不捕获处理,线程就会异常终止,当线程被唤醒后,再次进入就绪状态,等待资源。

      2.线程在执行过程中调用sleep()方法,进入睡眠状态,这个过程线程不会释放持有的资源,待睡眠时间完后即进入就绪状态,不会立即进入执行状态,因为线程调度机制恢复线程的运行也需要时间。当然睡眠状态也会被interrupt(0方法打断,效果和wait()一样。

      3.线程执行过程中,因为某些原因而使其停止执行。当线程阻塞后,别的贤臣就有机会执行,当线程阻塞被解除后进入就绪状态,等待被调度。

       阻塞原因有:

        a.线程调用sleep()方法放弃CPU时间片。

        b.线程调用wait()方法,等待别的线程来唤醒它。

        c.线程调用阻塞IO方法,方法返回前处于阻塞状态。(IO后面会分析)

        d.线程执行需要资源,在执行过程中,某些资源被别的线程持有,则该线程会处于阻塞状态来等待资源的获取。

        e.程序调用suspend()方法将该线程挂起,该方法容易产生死锁。

      4.线程进入死亡状态也是有原因的。

       死亡原因:

        a.线程执行完run()方法进入死亡状态。

        b.线程通过某种方式终止线程使其进入死亡状态(接下来分析)。

        c.线程抛出未捕获的线程使线程异常终止。

 

终止线程

      在早期的JDK中提供了stop()方法来终止线程,但是新版本不建议使用,提倡用布尔标记控制循环的停止来达到终止线程的目的。

      1.在循环体中,通过条件判断,符合条件的就break;跳出循环,终止线程。

      2.循环条件不要写成true,而是手动控制循环条件的false来达到终止线程的目的。

 

线程的调度

      1.线程执行前,通过优先级来达到线程调度的目的,优先级高的线程优先得到CPU执行。线程的优先级可以在程序中表明该线程的重要级,学过操作系统的都明白有很多的调度算法,这里不细说了。

      2.线程执行过程中,可以通过join()方法来调度线程,比如:

threadA = new Thread(new Runnable(){
	public void run() {
		for(int i = 0;i<=100;i++){
			if(i >= 50){
				threadB.join();
			}
		}
	}
});

      显然在线程A执行时,当i=50的时候,就会执行线程B,直到线程B执行完,线程A才会继续执行,这样也能达到线程调度的目的。

 

线程安全

      在多线程中,说到什么最重要,要属线程安全当之无愧,引入多线程的目的就是对大量任务进行有序的管理,通过多个任务混合使用,可以更有效的利用计算机的资源

      使用多线程,会发生两个以上的线程抢占资源的问题,必须防止资源访问的冲突。java提供线程同步机制可以防止资源访问的冲突(下篇分析)。

 

      欲知后事如何,请看下集。。。

分享到:
评论

相关推荐

    多线程文章目录

    Java多线程①——线程知识梳理 有助于新手初步了解线程相关的知识同时加深对基础的理解。 了解线程的状态、常用方法以及Thread、Runnable、Callable、Future、FutureTask这些基础概念和简单应用。 Java多线程②——...

    Java语音学习,基础教程

    初步掌握多线程:理解线程的概念,线程同步和Lock的用法,以及线程的生命周期。 以上这些是Java语言学习的主要内容,当然也可以根据实际应用的需要进行有针对性的学习。此外,建议在学习的过程中,不仅要学习理论...

    java之路,主要是java中的学习过程与基础项目.rar

    这部分主要学习的内容有:基本程序结构,类与对象,接口,泛型,反射,集合,异常与调试, Java 网络编程, Java I/O和多线程。 学 Java 基础,推荐大家看尚硅谷宋红康老师的 Java 教程,宋老师的课程更适合零基础...

    JAVA基础课程讲义

    JAVA中如何实现多线程(重点!!) 168 通过继承Thread类实现多线程 168 通过Runnable接口实现多线程 169 线程状态和sleep/yield/join/stop/destroy方法 170 新生状态 170 就绪状态 170 运行状态 170 死亡状态 170 ...

    达内java培训目录

    JavaSE核心 异常处理、多线程基础、IO系统、网络编程、Java反射机制、JVM性能调优(JVM内存结构剖析、GC分析及调优、JVM内存参数优化)、Java泛型、JDK新特性 熟练掌握JavaSE核心内容,特别是IO和多线程;初步具备...

    AIC的Java课程1-6章

     理解和应用Java异常,常用类,IO,集合和多线程等开发技术。  课时安排  总学时:52学时  授课:48学时 (含约20学时实验)  考试:4学时  预备知识  了解和使用操作系统,...

    《Java程序设计案例教程》课程标准.doc

    2.2知识目标 理解和掌握Java的基本语法和语义,掌握Java语言基础知识,初步掌握Java面向对象 编程的基本思想。 2.3素质目标 训练学生树立面向对象的编程思想、提高代码编写的熟练度和规范度,并开始接触企 业的应用...

    asp.net多线程的TCP端口扫描程序的设计与实现(源代码+论文)_new.rar

    对于学生而言,它提供了从初步的构想到实际开发所需的全方位辅助材料,包括论文、设计文档和源代码等。 2. 包含内容: - 论文:涵盖了整个Java ASP Web系统的基础知识,设计意图、需求概述、系统结构与设计哲学、...

    多生产者多消费者软件课设报告.doc

    生产者与消费者问题是经典进程同步问题的典型代表之一。该课程设计通过了解进程间的同步互斥关系,从而理解Java多线程通信机制;通过对经典进程同步问题的剖析,初步掌握运用Java多线程解决进程同步问题的方法。

    生产者消费者问题.ppt

    生产者与消费者问题是经典进程同步问题的典型代表之一。该课程设计通过了解进程间的同步互斥关系,从而理解Java多线程通信机制;通过对经典进程同步问题的剖析,初步掌握运用Java多线程解决进程同步问题的方法。

    《面向对象程序设计java)》课程整体教学设计.docx

    通过完成我爱追星、门禁系统、成绩管理、跑步比赛、键盘游戏图形界面程序,使学生能够熟深入理解面向对象的基本概念,熟练运用GUI、多线程、集合、JDBC等java编程技术,熟练运用面向对象程序设计的编程思想开发微型...

    Java-预备知识-Java基础

    语法、数组、面向对象、抽象类、接口、枚举、常用类、集合、泛型、注解、异常处理、多线程、IO 流、网络编程、反射。 学习目标:打下扎实的语言基础,深刻理解面向对象的抽象概念,具备初步编码能力,培养对于编程的...

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第一阶段05讲、采用多线程方式模拟银行排队叫号.mp4 │ 高并发编程第一阶段06讲、用Runnable接口将线程的逻辑执行单元从控制中抽取出来.mp4 │ 高并发编程第一阶段07讲、策略模式在Thread和Runnable...

    初步理解:jvm运行机制,java程序运行机制,堆栈详解,jvm调优的目的。

    谷咕咕最近在准备面试,本来想多看看堆和栈的关系,看看发现又设计到gc(Garbage Collection)垃圾回收机制,发现盲区太多了,就去粗略的学习了一下jvm(java虚拟机),发现之前只会写程序,底层的东西真是太丰富了...

    请求分页存储管理系统的设计与实现.rar

    通过《操作系统》课程实训,达到以下目的:(1)巩固和加深对操作系统(OS)原理的理解,初步掌握操作系统组成模块和应用接口的使用方法,提高进行工程设计和系统分析的能力;(2)通过相关课题的设计,锻炼学生解决...

    AndroidAll:Android程序员需要掌握的技术栈:数据结构算法,程序架构,设计模式,性能优化,插件化,热更新,Kotlin,NDK,Jetpack,以及常用的开源框架源码分析如Flutter,Router,RxJava, Glide,LeakCanary,Dagger2,Retrofit,OkHttp,ButterKnife等

    Java多线程,线程池,并发库 Java I / O,覆盖绝大部分I / O类 JVM虚拟机技术 深入了解Kotlin技术 Kotlin类型体系 Kotlin面向对象 Lambda表达式 高阶函数 彻底搞懂Kotlin泛型 Kotlin集合 操作符重载 Kotlin协程 ...

    Android开发艺术探索.任玉刚(带详细书签).pdf

    14.4 JNI调用Java方法的流程 486 第15章 Android性能优化 489 15.1 Android的性能优化方法 490 15.1.1 布局优化 490 15.1.2 绘制优化 493 15.1.3 内存泄露优化 493 15.1.4 响应速度优化和ANR日志分析 496 ...

    Android开发艺术探索

     14.4 JNI调用Java方法的流程 / 486  第15章 Android性能优化 / 489  15.1 Android的性能优化方法 / 490  15.1.1 布局优化 / 490  15.1.2 绘制优化 / 493  15.1.3 内存泄露优化 / 493  15.1.4 响应速度优化和...

    android开发艺术探索高清完整版PDF

    16 1.2.2 Activity的Flags / 27 1.3 Intent Filter的匹配规则 / 28 第2章 IPC机制 / 35 2.1 Android IPC简介 / 35 2.2 Android中的多进程模式 / 36 2.2.1 开启多进程模式 / 36 2.2.2 多进程模式的运行机制 / ...

Global site tag (gtag.js) - Google Analytics