多线程编程语言
❶ java多线程程序设计初步入门
在Java语言产生前 传统的程序设计语言的程序同一时刻只能单任务操作 效率非常低 例如程序往往在接收数据输入时发生阻塞 只有等到程序获得数据后才能继续运行 随着Internet的迅猛发展 这种状况越来越不能让人们忍受 如果网络接收数据阻塞 后台程序就处于等待状态而不继续任何操作 而这种阻塞是经常会碰到的 此时CPU资源被白白的闲置起来 如果在后台程序中能够同时处理多个任务 该多好啊!应Internet技术而生的Java语言解决了这个问题 多线程程序是Java语言的一个很重要的特点 在一个Java程序中 我们可以同时并行运行多个相对独立的线程 例如 我们如果创建一个线程来进行数据输入输出 而创建另一个线程在后台进行其它的数据处理 如果输入输出线程在接收数据时阻塞 而处理数据的线程仍然在运行 多线程程序设计大大提高了程序执行效率和处理能力
线程的创建
我们知道Java是面向对象的程序语言 用Java进行程序设计就是设计和使用类 Java为我们提供了线程类Thread来创建线程 创建线程与创建普通闹梁的类的对象的操作是一样的 而线程就是Thread类或其子类的实例对象 下面是一个创建启动一个线程的语句
Thread thread =new Thread(); file://声明困弯神一个对象实例 即创建一个线程
Thread run(); file://用Thread类中的run()方法启动线程
从这个例子 我们可以通过Thread()构造方法创建一个线程 并启动该线程 事实上 启动线程 也就是启动线程的run()方法 而Thread类中的run()方法没有任何操作语句 所以这个线程没有任何操作 要使线程实现预定功能 必须定义自己的run()方法 Java中通常有两种方式定义run()方法
通过定义一个Thread类的子类 在该子类中重写run()方法 Thread子类的实例对象就是一个线程 显然 该线程汪亏有我们自己设计的线程体run()方法 启动线程就启动了子类中重写的run()方法
通过Runnable接口 在该接口中定义run()方法的接口 所谓接口跟类非常类似 主要用来实现特殊功能 如复杂关系的多重继承功能 在此 我们定义一个实现Runnable() 接口的类 在该类中定义自己的run()方法 然后以该类的实例对象为参数调用Thread类的构造方法来创建一个线程
线程被实际创建后处于待命状态 激活(启动)线程就是启动线程的run()方法 这是通过调用线程的start()方法来实现的
下面一个例子实践了如何通过上述两种方法创建线程并启动它们
// 通过Thread类的子类创建的线程 class thread extends Thread { file://自定义线程的run()方法 public void run() { System out println( Thread is running… ); } } file://通过Runnable接口创建的另外一个线程 class thread implements Runnable { file://自定义线程的run()方法 public void run() { System out println( Thread is running… ); } } file://程序的主类 class Multi_Thread file://声明主类 { plubic static void mail(String args[]) file://声明主方法 { thread threadone=new thread (); file://用Thread类的子类创建线程 Thread threado=new Thread(new thread ()); file://用Runnable接口类的对象创建线程 threadone start(); threado start(); file://strat()方法启动线程 } }
运行该程序就可以看出 线程threadone和threado交替占用CPU 处于并行运行状态 可以看出 启动线程的run()方法是通过调用线程的start()方法来实现的(见上例中主类) 调用start()方法启动线程的run()方法不同于一般的调用方法 调用一般方法时 必须等到一般方法执行完毕才能够返回start()方法 而启动线程的run()方法后 start()告诉系统该线程准备就绪可以启动run()方法后 就返回start()方法执行调用start()方法语句下面的语句 这时run()方法可能还在运行 这样 线程的启动和运行并行进行 实现了多任务操作
线程的优先级
对于多线程程序 每个线程的重要程度是不尽相同 如多个线程在等待获得CPU时间时 往往我们需要优先级高的线程优先抢占到CPU时间得以执行 又如多个线程交替执行时 优先级决定了级别高的线程得到CPU的次数多一些且时间多长一些 这样 高优先级的线程处理的任务效率就高一些
Java中线程的优先级从低到高以整数 ~ 表示 共分为 级 设置优先级是通过调用线程对象的setPriority()方法 如上例中 设置优先级的语句为
thread threadone=new thread (); file://用Thread类的子类创建线程
Thread threado=new Thread(new thread ()); file://用Runnable接口类的对象创建线程
threadone setPriority( ); file://设置threadone的优先级
threado setPriority( ); file://设置threado的优先级
threadone start(); threado start(); file://strat()方法启动线程
这样 线程threadone将会优先于线程threado执行 并将占有更多的CPU时间 该例中 优先级设置放在线程启动前 也可以在启动后进行设置 以满足不同的优先级需求
线程的(同步)控制
一个Java程序的多线程之间可以共享数据 当线程以异步方式访问共享数据时 有时候是不安全的或者不和逻辑的 比如 同一时刻一个线程在读取数据 另外一个线程在处理数据 当处理数据的线程没有等到读取数据的线程读取完毕就去处理数据 必然得到错误的处理结果 这和我们前面提到的读取数据和处理数据并行多任务并不矛盾 这儿指的是处理数据的线程不能处理当前还没有读取结束的数据 但是可以处理其它的数据
如果我们采用多线程同步控制机制 等到第一个线程读取完数据 第二个线程才能处理该数据 就会避免错误 可见 线程同步是多线程编程的一个相当重要的技术
在讲线程的同步控制前我们需要交代如下概念
用Java关键字synchonized同步对共享数据操作的方法
在一个对象中 用synchonized声明的方法为同步方法 Java中有一个同步模型 监视器 负责管理线程对对象中的同步方法的访问 它的原理是 赋予该对象唯一一把 钥匙 当多个线程进入对象 只有取得该对象钥匙的线程才可以访问同步方法 其它线程在该对象中等待 直到该线程用wait()方法放弃这把钥匙 其它等待的线程抢占该钥匙 抢占到钥匙的线程后才可得以执行 而没有取得钥匙的线程仍被阻塞在该对象中等待
file://声明同步的一种方式 将方法声明同步
class store {public synchonized void store_in(){… }public synchonized void store_out(){ … }}
利用wait() notify()及notifyAll()方法发送消息实现线程间的相互联系
Java程序中多个线程通过消息来实现互动联系的 这几种方法实现了线程间的消息发送 例如定义一个对象的synchonized 方法 同一时刻只能够有一个线程访问该对象中的同步方法 其它线程被阻塞 通常可以用notify()或notifyAll()方法唤醒其它一个或所有线程 而使用wait()方法来使该线程处于阻塞状态 等待其它的线程用notify()唤醒
一个实际的例子就是生产和销售 生产单元将产品生产出来放在仓库中 销售单元则从仓库中提走产品 在这个过程中 销售单元必须在仓库中有产品时才能提货 如果仓库中没有产品 则销售单元必须等待
程序中 假如我们定义一个仓库类store 该类的实例对象就相当于仓库 在store类中定义两个成员方法 store_in() 用来模拟产品制造者往仓库中添加产品 strore_out()方法则用来模拟销售者从仓库中取走产品 然后定义两个线程类 customer类 其中的run()方法通过调用仓库类中的store_out()从仓库中取走产品 模拟销售者 另外一个线程类procer中的run()方法通过调用仓库类中的store_in()方法向仓库添加产品 模拟产品制造者 在主类中创建并启动线程 实现向仓库中添加产品或取走产品
如果仓库类中的store_in() 和store_out()方法不声明同步 这就是个一般的多线程 我们知道 一个程序中的多线程是交替执行的 运行也是无序的 这样 就可能存在这样的问题
仓库中没有产品了 销售者还在不断光顾 而且还不停的在 取 产品 这在现实中是不可思义的 在程序中就表现为负值 如果将仓库类中的stroe_in()和store_out()方法声明同步 如上例所示 就控制了同一时刻只能有一个线程访问仓库对象中的同步方法 即一个生产类线程访问被声明为同步的store_in()方法时 其它线程将不能够访问对象中的store_out()同步方法 当然也不能访问store_in()方法 必须等到该线程调用wait()方法放弃钥匙 其它线程才有机会访问同步方法
lishixin/Article/program/Java/gj/201311/27301
❷ 每个开发人员都应该知道的16个顶级新计算机编程语言
函数式语言
Elixir
Elixir 比 Erlang 更容易编写,具有 Haskell 等语言的函数式编程概念。Elixir是基于Erlang 虚拟机的,其广为人知的特点是运行低延时、分布式、可容错的系统,并成功用于Web开发与嵌入式软件领域。
Elm
Elm是一种用于构建 Web 应用程序的函数式语言。业内一般认为,它适用于创建高可交互应用,例如复杂的用户界面,开发人员可以通过 Elm 快速编写富有表现力的系统。Elm 也以没有运行时异常而闻名。
PureScript
PureScript是一种可编译为 JavaScript 的纯函数式编程语言。与 Haskell 最相似的是,PureScript 最适合用于开发 Web 应用程序和服务器端应用程序。
PureScript 支持类型推断,与其他语言相比,需要明显类型注释要少得多。
Swift
Swift是一种由苹果公司开发的通用编译编程语言,最早的设想是替代上一代编程语言Objective-C ,过程中结合了Objective-C、Rust、Ruby 和 Python等语言的编程思想。目前Swift用于开发苹果自己的手机、服务器、台式机上的应用软件。
程序语言
Go
Go语言是由谷歌公司创造的类似C风格的语言。Go 比 C++ 或 Java 更简洁,比 Ruby 或 Python 更安全。
一些缺点: 编码要求严格。比如,不能混用符号和无符号整数。还有一个明显的遗漏,Go语言没有泛型和继承。
但Go语言的优势同样明显,简单且易于使用。Go语言擅长于网络和多线程方面的编程。
面向对象语言
DART
Dart同样来自谷歌公司具有c语言风格。Dart可以轻松编写JavaScript、Java for Android、本地机器代码或独立的 Dart 虚拟机。它还可以运行后端代码。
Dart 非常适合使用事件驱动代码构建用户界面。根据Dart 团队成员的说法,Dart的优势:可选的静态类型、最小的编译时错误和强大的内置编辑器。
Pony
Pony是一种基于无数据竞争类型和垃圾收集的语言,并使用 actor 模型以及称为引用功能的东西。
你可以把 Pony 想象成某种“Rust 遇上 Erlang”的复合体,没有锁,高并发是其主要优点。
Pony 的缺点是 API 稳定性低、很少有高质量的第三方库和有限的本地工具。
TypeScript
TypeScript是一个基于 JavaScript 静态类型定义构建,并由微软维护且开源编程语言。Visual Studio Code 或Visual Studio 是推荐的IDE编辑器,微软大厂的用户体验和错误检查也不用怀疑。
复合编程语言
Hack
Hack是一种作为 PHP 方言的 HipHop 虚拟机的编程语言。于 2014 年由Facebook创建,允许程序员同时使用静态和动态类型(也称为渐进类型),这为编码提供了灵活性。
Julia
Julia是一种高级通用编程语言,用于计算科学和数值分析。Julia 以动态类型和可重现的高性能特性而闻名。
Julia 在数据可视化和机器学习等方面都有大量用途。事实上,它被英国保险公司 Aviva 用于风险计算,纽约联邦储备银行用于金融建模,甚至气候建模联盟用于气候变化建模。它拥有Fortran、C++、R、Java、C 、Python等的接口,这使其成为最受追捧的新语言之一。
Kotlin
Kotlin是运行在 Java 虚拟机中的更快、更流畅的 Java 版本。它现在是Android 开发的首选语言。根据 Android 开发者网站显示,程序员正转而采用 Kotlin,因为该语言的样板代码更少,空指针异常更少,并且与 Java 有互操作性。
Kotlin 可用于在 iOS 和 Android 上运行的应用程序、不使用额外运行时或虚拟机。
Nim
Nim是一种优先考虑可读性的静态类型语言。通过结合多种语言的特性,Nim 为程序员提供了速度和易用性。
它带有 JavaScript 后端、分散的包管理、自动内存管理、C 和 C++ 库的绑定以及用于调试的回溯。作为一种语言,Nim 是有限的,但它包含一组元编程功能,如泛型、模板和宏,因此开发人员可以在避免冗长代码的同时以不同的风格工作。
OCaml作为此列表中较旧的语言,OCaml是一种多范式语言——既有函数式、命令式和类型安全,也具有面向对象功能。
OCaml 的一些优势:定义数据类型很容易。默认情况下,所有变量都是不可变的。API 稳定,具有良好的库向后兼容性。该语言还为独立应用程序提供自动内存管理和单独编译。
Reason
如果比JavaScript 更快、更简单且类型安全会怎样?
这就是创建Reason的 Facebook 开发者想要回答的问题。不过,他并没有从头开始构建一种新语言,而是采用了 OCaml,并将其调整为类似于 JavaScript。
Reason使用项目 BucketScript编译为 JavaScript,并且可以访问 80% 的 JavaScript 工具和生态系统。它还可以编译为准系统、iOS、Android 和微控制器。
Red
Red是一种最初旨在克服 Rebol 语言限制的编程语言。Red 于 2011 年推出,受 Rebol、Lua 和 Scala 等语言的影响,对高级和低级编程都很有用。
该语言可用于开发从高级 GUI 到低级操作系统的所有方面。Red 拥有人性化的语法、低内存占用和垃圾收集等优点。
Rust
Rust解决了一些与 Go 相同的问题,如系统级别的线程和进程安全,,但Rust 更像 C 风格的语法
但Rust语言的缺点:静态类型和缺乏垃圾收集
Rust可直接访问内存意味着程序员可以编写低级代码,如操作系统内核。Rust 也非常适合嵌入式设备、网络服务和命令行编写。
❸ c语言如何编写一个简单的多线程程序
这是一个多线程例子,里面只有两个线程,是生产者/消费者模式,已编译通过,注释很详细,x0dx0a如下:x0dx0ax0dx0a/* 以生产者和消费者模型问题来阐述Linux线程的控制和通信你 x0dx0a 生产者线程将生产的产品送入缓冲区,消费者线程则从中取出产品。x0dx0a 缓冲区有N个,是一个环形的缓冲池。x0dx0a */x0dx0a#include
❹ C语言多线程的优势
线程程序作为一种多任务、并发的工作方式,当然有其存在优势:
提高应用程序响应:
这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
使多CPU系统更加有效:
操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
改善程序结构:
一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
❺ 关于C++多线程编程教学
在Windows NT和Windows 9x中,多线程的编程实现需要调用一系列的API函数,如CreateThread、ResumeThread等,比较麻烦而且容易出错。我们使用Inprise公司的新一代RAD开发工具C++Builder,可以方便地实现多线程的编程。与老牌RAD工具Visual Basic和Delphi比,C++Builer不仅功能非常强大,而且它的编程语言是C++,对于系统开发语言是C的Windows系列操作系统,它具有其它编程语言无可比拟的优势。利用C++Builder提供的TThread对象,多线程的编程变得非常简便易用。那么,如何实现呢?且待我慢慢道来,让你体会一下多线程的强大功能。
1. 创建多线程程序:
首先,先介绍一下实现多线程的具体步骤。在C++Builder中虽然用Tthread对象说明了线程的概念,但是Tthread对象本身并不完整,需要在TThread下新建其子类,并重载Execute方法来使用线程对象。在C++Builder下可以很方便地实现这一点。
在C++Builder IDE环境下选择菜单File|New,在New栏中选中Thread Object,按OK,接下来弹出输入框,输入TThread对象子类的名字MyThread,这样C++Builder自动为你创建了一个名为TMyThread的TThread子类。同时编辑器中多了一个名为Unit2.cpp的单元,这就是我们创建的TMyThread子类的原码,如下:
#include
#pragma hdrstop
#include “Unit2.h”
#pragma package(smart_init)
//---------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall MyThread::UpdateCaption()
// {
// Form1->Caption = “Updated in a thread”;
// }
//--------------------
__fastcall MyThread::MyThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//--------------------
void __fastcall MyThread::Execute()
{
//---- Place thread code here ----
}
//---------------------
其中的Execute()函数就是我们要在线程中实现的任务的代码所在处。在原代码中包含Unit2.cpp,这个由我们创建的TMyThread对象就可以使用了。使用时,动态创建一个TMyThread 对象,在构造函数中使用Resume()方法,那么程序中就增加了一个新的我们自己定义的线程TMyThread,具体执行的代码就是Execute()方法重载的代码。要加载更多的线程,没关系,只要继续创建需要数量的TMyThread 对象就成。
❻ 什么是Java多线程
多线程的概念?
说起多线程,那么就不得不说什么是线程,而说起线程,又不得不说什么是进程。
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
进程可以简单的理解为一个可以独立运行的程序单位。它是线程的集合,进程就是有一个或多个线程构成的,每一个线程都是进程中的一条执行路径。
那么多线程就很容易理解:多线程就是指一个进程中同时有多个执行路径(线程)正在执行。
为什么要使用多线程?
1.在一个程序中,有很多的操作是非常耗时的,如数据库读写操作,IO操作等,如果使用单线程,那么程序就必须等待这些操作执行完成之后才能执行其他操作。使用多线程,可以在将耗时任务放在后台继续执行的同时,同时执行其他操作。
2.可以提高程序的效率。
3.在一些等待的任务上,如用户输入,文件读取等,多线程就非常有用了。
缺点:
1.使用太多线程,是很耗系统资源,因为线程需要开辟内存。更多线程需要更多内存。
2.影响系统性能,因为操作系统需要在线程之间来回切换。
3.需要考虑线程操作对程序的影响,如线程挂起,中止等操作对程序的影响。
4.线程使用不当会发生很多问题。
总结:多线程是异步的,但这不代表多线程真的是几个线程是在同时进行,实际上是系统不断地在各个线程之间来回的切换(因为系统切换的速度非常的快,所以给我们在同时运行的错觉)。
2.多线程与高并发的联系。
高并发:高并发指的是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问或者socket端口集中性收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。如果高并发处理不好,不仅仅降低了用户的体验度(请求响应时间过长),同时可能导致系统宕机,严重的甚至导致OOM异常,系统停止工作等。如果要想系统能够适应高并发状态,则需要从各个方面进行系统优化,包括,硬件、网络、系统架构、开发语言的选取、数据结构的运用、算法优化、数据库优化……。
而多线程只是在同/异步角度上解决高并发问题的其中的一个方法手段,是在同一时刻利用计算机闲置资源的一种方式。
多线程在高并发问题中的作用就是充分利用计算机资源,使计算机的资源在每一时刻都能达到最大的利用率,不至于浪费计算机资源使其闲置。
3.线程的创建,停止,常用方法介绍。
1.线程的创建:
线程创建主要有2种方式,一种是继承Thread类,重写run方法即可;(Thread类实现了Runable接口)
另一种则是实现Runable接口,也需要重写run方法。
线程的启动,调用start()方法即可。 我们也可以直接使用线程对象的run方法,不过直接使用,run方法就只是一个普通的方法了。
其他的还有: 通过匿名内部类的方法创建;实现Callable接口。。。。。
2.线程常用方法:
currentThread()方法:该方法返回当前线程的信息 .getName()可以返回线程名称。
isAlive()方法:该方法判断当前线程是否处于活动状态。
sleep()方法:该方法是让“当前正在执行的线程“休眠指定的时间,正在执行的线程是指this.currentThread()返回的线程。
getId()方法:该方法是获取线程的唯一标识。
3.线程的停止:
在java中,停止线程并不简单,不想for。。break那样说停就停,需要一定的技巧。
线程的停止有3种方法:
1.线程正常终止,即run()方法运行结束正常停止。
2.使用interrupt方法中断线程。
3.使用stop方法暴力停止线程。
interrupt方法中断线程介绍:
interrupt方法其实并不是直接中断线程,只是给线程添加一个中断标志。
判断线程是否是停止状态:
this.interrupted(); 判断当前线程是否已经中断。(判断的是这个方法所在的代码对应的线程,而不是调用对象对应的线程)
this.isInterrupted(); 判断线程是否已经中断。(谁调用,判断谁)
注:.interrupted()与isInterrupted()的区别:
interrupted()方法判断的是所在代码对应的线程是否中断,而后者判断的是调用对象对应的线程是否停止
前者执行后有清除状态的功能(如连续调用两次时,第一次返回true,则第二次会返回false)
后者没有清除状态的功能(两次返回都为true)
真正停止线程的方法:
异常法:
在run方法中 使用 this.interrupted();判断线程终止状态,如果为true则 throw new interruptedException()然后捕获该异常即可停止线程。
return停止线程:
在run方法中 使用 this.interrupted();判断线程终止状态,如果为true则return停止线程。 (建议使用异常法停止线程,因为还可以在catch中使线程向上抛,让线程停止的事件得以传播)。
暴力法:
使用stop()方法强行停止线程(强烈不建议使用,会造成很多不可预估的后果,已经被标记为过时)
(使用stop方法会抛出 java.lang.ThreadDeath 异常,并且stop方法会释放锁,很容易造成数据不一致)
注:在休眠中停止线程:
在sleep状态下停止线程 会报异常,并且会清除线程状态值为false;
先停止后sleep,同样会报异常 sleep interrupted;
4.守护线程。
希望对您有所帮助!~
❼ Java多线程编程
作者 natrium 一 理解多线程多线程是这样一种机制 它允许在程序中并发执行多个指令流 每个指令流都称为一个线程 彼此间互相独立 线程又称为轻量级进程 它和进程一样拥有独立的执行控制 由操作系统负责调度 区别在于线程没有独立的存储空间 而是和所属进程中的其它线程共享一个存储空间 这使得线程间的通信远较进程简单 多个线程的执行是并发的 也就是在逻辑上 同时 而不管是否是物理上的 同时 如果系统只有一个CPU 那么真正的 同时 是不可能的 但是由于CPU的速度非常快 用户感觉不到其中的区别 因此我们也不用关心它 只需要设想各个线程是同时执行即可 多线程和传统的单线程在程序设计上最大的区别在于 由于各个线程的控制流彼此独立 使得各个线程之间的代码是乱序执行的 由此带来的线程调度 同步等问题 将在以后探讨 二 在Java中实现多线程我们不妨设想 为了创建一个新的线程 我们需要做些什么?很显然 我们必须指明这个线程所要执行的代码 而这就是在Java中实现多线程我们所需要做的一切!真是神奇!Java是如何做到这一点的?通过类!作为一个完全面向对象的语言 Java提供了类 java lang Thread 来方便多线程编程 这个类提供了大量的方法来方便我们控制自己的各个线程 我们以后的讨论都将围绕这个类进行 那么如何提供给 Java 我们要线程执行的代码呢?让我们来看一看 Thread 类 Thread 类最重要的方法是 run() 它为Thread 类的方法 start() 所调用 提供我们的线程所要执行的代码 为了指定我们自己的代码 只需要覆盖它!方法一 继承 Thread 类 覆盖方法 run() 我们在创建的 Thread 类的子类中重写 run() 加入线程所要执行的代码即可 下面是一个例子 public class MyThread extends Thread {int count= number;public MyThread(int num) {number = num;System out println( 创建线程 + number);}public void run() {while(true) {System out println( 线程 + number + :计数 + count);if(++count== ) return;}}public static void main(String args[]) {for(int i = ; i < 5; i++) new MyThread(i+1).start();}}这种方法简单明了,符合大家的习惯,但是,它也有一个很大的缺点,那就是如果我们的类已经从一个类继承(如小程序必须继承自 Applet 类),则无法再继承 Thread 类,这时如果我们又不想建立一个新的类,应该怎么办呢?我们不妨来探索一种新的方法:我们不创建 Thread 类的子类,而是直接使用它,那么我们只能将我们的方法作为参数传递给 Thread 类的实例,有点类似回调函数。.WINgWIT.但是 Java 没有指针,我们只能传递一个包含这个方法的类的实例。那么如何限制这个类必须包含这一方法呢?当然是使用接口!(虽然抽象类也可满足,但是需要继承,而我们之所以要采用这种新方法,不就是为了避免继承带来的限制吗?)Java 提供了接口 java.lang.Runnable 来支持这种方法。方法二:实现 Runnable 接口Runnable 接口只有一个方法 run(),我们声明自己的类实现 Runnable 接口并提供这一方法,将我们的线程代码写入其中,就完成了这一部分的任务。但是 Runnable 接口并没有任何对线程的支持,我们还必须创建 Thread 类的实例,这一点通过 Thread 类的构造函数public Thread(Runnable target);来实现。下面是一个例子:public class MyThread implements Runnable {int count= 1, number;public MyThread(int num) {number = num;System.out.println("创建线程 " + number);}public void run() {while(true) {System.out.println("线程 " + number + ":计数 " + count);if(++count== 6) return;} }public static void main(String args[]) {for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();}}严格地说,创建 Thread 子类的实例也是可行的,但是必须注意的是,该子类必须没有覆盖 Thread 类的 run 方法,否则该线程执行的将是子类的 run 方法,而不是我们用以实现Runnable 接口的类的 run 方法,对此大家不妨试验一下。使用 Runnable 接口来实现多线程使得我们能够在一个类中包容所有的代码,有利于封装,它的缺点在于,我们只能使用一套代码,若想创建多个线程并使各个线程执行不同的代码,则仍必须额外创建类,如果这样的话,在大多数情况下也许还不如直接用多个类分别继承 Thread 来得紧凑。综上所述,两种方法各有千秋,大家可以灵活运用。下面让我们一起来研究一下多线程使用中的一些问题。三:线程的四种状态1. 新状态:线程已被创建但尚未执行(start() 尚未被调用)。2. 可执行状态:线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行。3. 死亡状态:正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁。4. 阻塞状态:线程不会被分配 CPU 时间,无法执行。四:线程的优先级 线程的优先级代表该线程的重要程度,当有多个线程同时处于可执行状态并等待获得 CPU 时间时,线程调度系统根据各个线程的优先级来决定给谁分配 CPU 时间,优先级高的线程有更大的机会获得 CPU 时间,优先级低的线程也不是没有机会,只是机会要小一些罢了。你可以调用 Thread 类的方法 getPriority() 和 setPriority()来存取线程的优先级,线程的优先级界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之间,缺省是5(NORM_PRIORITY)。五:线程的同步由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:public synchronized void accessVal(int newVal);synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下: synchronized(syncObject) {//允许访问控制的代码}synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。六:线程的阻塞为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题,Java 引入了对阻塞机制的支持。阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞,下面让我们逐一分析。1. sleep() 方法:sleep() 允许 指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。2. suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后 lishixin/Article/program/Java/gj/201311/27622
❽ 什么是Java多线程编程
一、 什么是多线程:
我们现在所使用操作系统都是多任务操作系统(早期使用的DOS操作系统为单任务操作系统),多任务操作指在同一时刻可以同时做多件事(可以同时执行多个程序)。
多进程:每个程序都是一个进程,在操作系统中可以同时执行多个程序,多进程的目的是为了有效的使用CPU资源,每开一个进程系统要为该进程分配相关的系统资源(内存资源)
多线程:线程是进程内部比进程更小的执行单元(执行流|程序片段),每个线程完成一个任务,每个进程内部包含了多个线程每个线程做自己的事情,在进程中的所有线程共享该进程的资源;
主线程:在进程中至少存在一个主线程,其他子线程都由主线程开启,主线程不一定在其他线程结束后结束,有可能在其他线程结束前结束。Java中的主线程是main线程,是Java的main函数;
继承Thread类来实现多线程:
二、 Java中实现多线程的方式:
当我们自定义的类继承Thread类后,该类就为一个线程类,该类为一个独立的执行单元,线程代码必须编写在run()方法中,run方法是由Thread类定义,我们自己写的线程类必须重写run方法。
run方法中定义的代码为线程代码,但run方法不能直接调用,如果直接调用并没有开启新的线程而是将run方法交给调用的线程执行
要开启新的线程需要调用Thread类的start()方法,该方法自动开启一个新的线程并自动执行run方法中的内容
java多线程的启动顺序不一定是线程执行的顺序,各个线程之间是抢占CPU资源执行的,所有有可能出现与启动顺序不一致的情况。
CPU的调用策略:
如何使用CPU资源是由操作系统来决定的,但操作系统只能决定CPU的使用策略不能控制实际获得CPU执行权的程序。
线程执行有两种方式:
1.抢占式:
目前PC机中使用最多的一种方式,线程抢占CPU的执行权,当一个线程抢到CPU的资源后并不是一直执行到此线程执行结束,而是执行一个时间片后让出CPU资源,此时同其他线程再次抢占CPU资源获得执行权。
2.轮循式;
每个线程执行固定的时间片后让出CPU资源,以此循环执行每个线程执行相同的时间片后让出CPU资源交给下一个线程执行。
希望对您有所帮助!~