java 多线程 并发编程_Java多线程与并发编程总结 PDF 下载

本文详细介绍了多任务、多进程和多线程的概念,从操作系统的角度出发,解释了它们如何提高系统效率。Java中的多线程实现方式包括继承Thread类和实现Runnable接口,线程的并发执行给人一种宏观上的“同时”执行感,但实际上是由CPU快速切换执行。Java虚拟机采用抢占式调度模式,线程的执行顺序是不确定的,这为程序员提供了乱序执行的代码设计空间。
摘要由CSDN通过智能技术生成

主要内容:

认识多任务、多进程、单线程、多线程

要认识多线程就要从操作系统的原理说起。

以前古老的DOS操作系统(V 6.22)是单任务的,还没有线程的概念,系统在每次只能做一件事情。比如你在copy东西的时候不能rename文件名。为了提高系统的利用效率,采用批处理来批量执行任务。

现在的操作系统都是多任务操作系统,每个运行的任务就是操作系统所做的一件事情,比如你在听歌的同时还在用MSN和好友聊天。听歌和聊天就是两个任务,这个两个任务是“同时”进行的。一个任务一般对应一个进程,也可能包含好几个进程。比如运行的MSN就对应一个MSN的进程,如果你用的是windows系统,你就可以在任务管理器中看到操作系统正在运行的进程信息。

一般来说,当运行一个应用程序的时候,就启动了一个进程,当然有些会启动多个进程。启动进程的时候,操作系统会为进程分配资源,其中最主要的资源是内存空间,因为程序是在内存中运行的。在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可以同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程。当多个线程同时运行的时候,这样的执行模式成为并发执行。

多线程的目的是为了最大限度的利用CPU资源。

Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。

一般常见的Java应用程序都是单线程的。比如,用java命令运行一个最简单的HelloWorld的Java应用程序时,就启动了一个JVM进程,JVM找到程序程序的入口点main(),然后运行main()方法,这样就产生了一个线程,这个线程称之为主线程。当main方法结束后,主线程运行完成。JVM进程也随即退出。

对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难。

实际上,操作的系统的多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。多任务、多进程、多线程的前提都是要求操作系统提供多任务、多进程、多线程的支持。

在Java程序中,JVM负责线程的调度。线程调度是值按照特定的机制为多个线程分配CPU的使用权。

调度的模式有两种:分时调度和抢占式调度。分时调度是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;抢占式调度是根据线程的优先级别来获取CPU的使用权。JVM的线程调度模式采用了抢占式模式。

所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。众所周知,CPU都有个时钟频率,表示每秒中能执行cpu指令的次数。在每个时钟周期内,CPU实际上只能去执行一条(也有可能多条)指令。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段是时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。

用一句话做总结:虽然操作系统是多线程的,但CPU每一时刻只能做一件事,和人的大脑是一样的,呵呵。

Java语言的多线程需要操作系统的支持。

Java 虚拟机允许应用程序并发地运行多个执行线程。Java语言提供了多线程编程的扩展点,并给出了功能强大的线程控制API。

在Java中,多线程的实现有两种方式:

扩展java.lang.Thread类

实现java.lang.Runnable接口

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:

调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。

非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。

扩展java.lang.Thread类

运行结果:

main 线程运行开始!

main 线程运行结束!

A 线程运行开始!

0 A

1 A

B 线程运行开始!

2 A

0 B

3 A

4 A

1 B

5 A

6 A

7 A

8 A

9 A

A 线程运行结束!

2 B

3 B

4 B

5 B

6 B

7 B

8 B

9 B

B 线程运行结束!

说明:

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用MitiSay的两个对象的start方法,另外两个线程也启动了,这样,整个应用就在多线程下运行。

在一个方法中调用Thread.currentThread().getName()方法,可以获取当前线程的名字。在mian方法中调用该方法,获取的是主线程的名字。

注意:start()方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行是由操作系统决定的。

从程序运行的结果可以发现,多线程程序是乱序执行。因此,只有乱序执行的代码才有必要设计为多线程。

Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。

实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.得到服务器下载文件的大小,然后在本地设置一个临时文件和服务器端文件大小一致 a)获得访问网络地址 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout iii.setReadTimeout d)判断是否响应成功 e)获取文件长度(getContentLength()) f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)设置临时文件与服务器文件大小一致(setLength()) h)关闭临时文件 2.计算出每个线程下载的大小(开始位置,结束位置) a)计算出每个线程下载的大小 b)for循环,计算出每个线程的开始、结束位置 c)最后一个线程处理 3.每创建好一次就要开启线程下载 a)构造方法 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout d)判断是否响应成功(206) e)获取每个线程返回的流对象 f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)指定开始位置 h)循环读取 i.保存每个线程下载位置 ii.记录每次下载位置 iii.关闭临时记录位置文件 iv.随机本地文件写入 v.记录已下载大小 i)关闭临时文件 j)关闭输入流 4.为了杀死线程还能继续下载的情况下,从本地文件上读取已经下载文件的开始位置 a)创建保存记录结束位置的文件 b)读取文件 c)将流转换为字符 d)获取记录位置 e)把记录位置赋给开始位置 5.当你的n个线程都下载完毕的时候我进行删除记录下载位置的缓存文件 a)线程下载完就减去 b)当没有正在运行的线程时切文件存在时删除文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值