- 浏览: 47600 次
- 性别:
- 来自: 武汉
文章分类
最新评论
多线程(认识多线程、线程的常用操作方法)
认识多线程
进程与线程:
进程是程序的一次动态执行过程,它经历了从代码加载、到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。
多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。
Java的多线程实现,有一下两种方式:
·继承Thread类
·实现Runnable接口
Thread类
Thread类是在java.lang包下定义的,一个类只要继承了Thread类,此类就称为多线程操作类。在Thread子类中,必须明确的腹泻Thread中的run()方法,此方法称为线程的主体。
·多线程的定义语法:
- class类名称extendsThread{//继承Thread类
- 属性...;//类中定义属性
- 方法...;//类中定义方法
- //覆写Thread中的run()方法,此方法是线程的主体
- publicvoidrun(){
- 线程主体;
- }
- }
如以下的一个类中就具备了多线程的操作功能:
- classMyThreadextendsThread//继承自Thread类
- {
- privateStringname;//表示线程的名称
- publicMyThread(Stringname){
- this.name=name;//通过构造方法配置name属性
- }
- publicvoidrun(){//覆写run方法,作为线程的主体
- for(inti=0;i<10;i++){
- System.out.println(name+"运行,i="+i);
- }
- }
- }
实例化该类以后,通过对象可以调用run方法:
- publicclassThreadDemo01
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread("A");//实例化MyThread类
- MyThreadm1=newMyThread("B");
- m.run();//调用run方法
- m1.run();
- }
- }
同过程序的运行结果可以发现,程序是先执行A后再执行B的,并没有达到所谓的并发执行的效果,如果是想要启动一个线程必须要使用Thread类中定义的start()方法。
- publicclassThreadDemo01
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread("A");//实例化MyThread类
- MyThreadm1=newMyThread("B");
- m.start();//调用Thread类中定义的start启动一个线程
- m1.start();
- }
- }
注意:如果当前线程已经启动了(就是说已经调用了start方法),再次调用start方法就会出现java.lang.IllegalThreadStateException异常
Runnable接口
在Java中也可以通过实现Runnable接口的方式实现多线程,Runnable接口中只定义了一个抽象方法:
·public void run();
通过Runnable接口实现多线程:
- class类名称implementsRunnable//实现Runnable接口
- {
- 属性...;//类中定义属性
- 方法...;//类中定义方法
- publicvoidrun(){//覆写Runnable接口中的run方法
- 线程主体;
- }
- }
如以下代码:
- classMyThreadimplementsRunnable//继承自Thread类
- {
- privateStringname;//表示线程的名称
- publicMyThread(Stringname){
- this.name=name;//通过构造方法配置name属性
- }
- publicvoidrun(){//覆写run方法,作为线程的主体
- for(inti=0;i<10;i++){
- System.out.println(name+"运行,i="+i);
- }
- }
- }
- publicclassThreadDemo02
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm1=newMyThread("A");//实例化对象
- MyThreadm2=newMyThread("B");
- Threadt1=newThread(m1);//实例化Thread类
- Threadt2=newThread(m2);
- t1.start();//启动线程
- t2.start();
- }
- }
以上代码通过实现Runnable接口实现了多线程,但是要注意的是,一个线程启动的方法是在Thread类中的start()方法,此时Runnable接口中是没有该方法的,所以要实例化Thread类,调用其start方法。
Runnable接口与Thread类的区别
使用Thread类在操作多线程的时候无法达到资源共享的目的,而使用Runnable接口实现的多线程操作可以实现资源共享。如以下的代码:
实现Runnable接口:
- classMyThreadimplementsRunnable//继承自Thread类
- {
- privateintNumber1=5;//表示线程的名称
- publicvoidrun(){//覆写run方法,作为线程的主体
- for(inti=0;i<100;i++){
- if(Number1>0)
- System.out.println("ticket"+Number1--);
- }
- }
- }
- publicclassThreadDemo02
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread();
- newThread(m).start();
- newThread(m).start();
- }
- }
此时可以发现启动了两个线程,但是票的总数是5。
继承自Thread类:
- classMyThreadextendsThread//继承自Thread类
- {
- privateintNumber1=5;//表示线程的名称
- publicvoidrun(){//覆写run方法,作为线程的主体
- for(inti=0;i<100;i++){
- if(Number1>0)
- System.out.println("ticket"+Number1--);
- }
- }
- }
- publicclassThreadDemo03
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm1=newMyThread();
- MyThreadm2=newMyThread();
- MyThreadm3=newMyThread();
- m1.start();//启动线程
- m2.start();//启动线程
- m3.start();//启动线程
- }
- }
此时启动了三个线程,票的总数就是15,因为在每一个MyThread对象中都包含各自的ticket属性。
Thread类与Runnable接口的使用结论
实现Runnable接口比继承Thread类有如下明显的优点:
·适合多个相同程序代码的线程去处理同一个资源。
·可以避免由于单继承局限所带来的影响。
·增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
综合以上来看:开发中使用Runnable接口是比较合适的,应该充分使用其以上特性。
线程的状态
多线程在操作中也是有一个固定的操作状态的:
·创建对象:准备好了一个多线程的对象: Thread t=new Thread();
·就绪状态:调用了start()方法,等待CPU进行调度。
·运行状态:执行了run()方法。
·阻塞状态:暂时停止执行,可能将资源交给其它资源使用。
·终止状态(死亡状态):线程执行完毕,不再进行使用。
线程的常用操作方法
取得当前线程的名称
程序可以通过currentThread()方法取得当前正在运行的线程的名称。代码如下:
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){//覆写run方法
- System.out.println(Thread.currentThread().getName()+"运行");
- }
- }
- publicclasscurrentThreadDemo
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread();//实例化Runnable子类对象
- newThread(m).start();//让JVM为线程设置名称并启动
- newThread(m,"线程").start();//为线程设置名称并启动线程
- m.run();//直接调用run方法获得当前main方法线程名称
- //程序输出
- //Thread-0运行
- //main运行
- //线程运行
- }
- }
由以上代码可以得知:如果不为一个线程设置名称,则JVN自动按Thread-0、Thread-1、Thread-2、….的格式为线程设置名称。注意:main方法的线程名称为main
扩展:既然主方法都是以线程的形式出现的,那么JAVA运行时至少应该是启动了两个线程。每当JAVA程序运行的时候,实际上都启动了一个JVM,每一个JVM实际上就是在操作系统中启动了一个进程,java本身具有垃圾收集机制,所以Java运行时至少启动了两个线程:
主线程、GC(垃圾回收的线程)
判断线程是否启动
判断线程是否启动使用isAlive()方法,返回boolean得到当前线程是否活动。
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){//覆写run方法
- System.out.println(Thread.currentThread().getName()+"运行");
- }
- }
- publicclassThreadAliveDemo
- {
- publicstaticvoidmain(Stringargs[])throwsIllegalThreadStateException{
- MyThreadm=newMyThread();//实例化Runnable子类对象
- Threadt=newThread(m,"自定义线程");
- System.out.println("线程执行前:"+t.isAlive());//false
- t.start();
- System.out.println("线程启动之后:"+t.isAlive());//true
- }
- }
线程的强制运行
在线程操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其它线程无法运行,必须等待此线程完成之后才可以继续执行。
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){//覆写run方法
- for(inti=0;i<50;i++){
- System.out.println(Thread.currentThread().getName()+"运行,i="+i);
- }
- }
- }
- publicclassThreadJoinDemo
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread();//实例化Runnable子类对象
- Threadt=newThread(m,"自定义线程");
- t.start();
- for(inti=0;i<50;i++){
- if(i>10)
- try{
- //join方法会出现异常
- t.join();
- }catch(InterruptedExceptione){
- }
- System.out.println("main线程运行,i="+i);
- }
- }
- }
以上代码中,程序一开始自定义跟main线程会交替运行,但是当main线程中i+10时,就会强制的先执行自定义线程,待其执行完以后,再执行main线程,这就是线程的强制运行。
线程的休眠
在程序中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){//覆写run方法
- for(inti=0;i<50;i++){
- try{
- //sleep方法会出现异常
- Thread.sleep(1000);//程序会暂停1000毫秒再执行
- }catch(InterruptedExceptione){
- }
- System.out.println(Thread.currentThread().getName()+"运行,i="+i);
- }
- }
- }
- publicclassThreadSleepDemo
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread();//实例化Runnable子类对象
- Threadt=newThread(m,"自定义线程");
- t.start();
- }
- }
以上的程序会间隔1秒钟执行一次。Sleep()方法就时暂时的休眠,指定了一定了的时间后程序会继续执行。
线程的中断
一个线程可以被另一个线程中断其操作的状态,使用interrupt()方法。
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){//覆写run方法
- try{
- //sleep方法会出现异常
- System.out.println("1、进入run方法");
- Thread.sleep(2000);//程序会暂停1000毫秒再执行
- System.out.println("2、已经完成了休眠");
- }catch(InterruptedExceptione){
- System.out.println("3、休眠被终止!");
- return;//返回方法调用处
- }
- System.out.println("4、run方法正常结束");
- }
- }
- publicclassThreadInterruptDemo
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm=newMyThread();//实例化Runnable子类对象
- Threadt=newThread(m,"自定义线程");
- t.start();
- try{
- //sleep方法会出现异常
- Thread.sleep(10000);
- }catch(InterruptedExceptione){
- }
- t.interrupt();
- }
- }
后台线程
在Java程序中,只要前台有一个线程在运行,则整个Java进程都不会消失,所以此时可以设置一个后台线程,这样即使Java进程结束了,此后台线程依然会执行。要想实现这样的操作,直接使用setDaemon()方法即可。
- classMyThreadimplementsRunnable{//实现Runnable接口
- publicvoidrun(){//覆写run()方法
- while(true){
- System.out.println(Thread.currentThread().getName()+"在运行。");
- }
- }
- };
- publicclassThreadDaemonDemo{
- publicstaticvoidmain(Stringargs[]){
- MyThreadmt=newMyThread();//实例化Runnable子类对象
- Threadt=newThread(mt,"线程");//实例化Thread对象
- t.setDaemon(true);//此线程在后台运行
- t.start();//启动线程
- }
- };
此方法了解即可,不重要。
线程的优先级
优先级越高的线程,被执行的顺序就比较靠前,在Thread中存在三个常量:MAX_PRIORITY、
MIN_PRIORITY、NORM_PRIORITY执行顺序为:MAX_PRIORITY> NORM_PRIORITY>
MIN_PRIORITY、代码如下:
- classMyThreadimplementsRunnable//实现Runnable接口
- {
- publicvoidrun(){
- System.out.println(Thread.currentThread().getName());
- }
- }
- publicclassThreadPriorDemo
- {
- publicstaticvoidmain(Stringargs[]){
- Threadt1=newThread(newMyThread(),"线程A");
- Threadt2=newThread(newMyThread(),"线程B");
- Threadt3=newThread(newMyThread(),"线程C");
- t1.setPriority(Thread.MAX_PRIORITY);
- t2.setPriority(Thread.NORM_PRIORITY);
- t3.setPriority(Thread.MIN_PRIORITY);
- t1.start();
- t2.start();
- t3.start();
- }
- }
实际上:MAX_PRIORITY=10、 NORM_PRIORITY=5、MIN_PRIORITY=1
同步与死锁
先看如以下的代码:
- classMyThreadimplementsRunnable{
- intticket=5;//假设一共有5张票
- publicvoidrun(){
- for(inti=0;i<50;i++){
- if(ticket>0){//还有票的话就继续卖
- try{
- Thread.sleep(500);//为了保证正确,加入延迟
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- System.out.println("卖票:ticeket="+ticket--);
- }
- }
- }
- }
- publicclasssynchronizedDemo02
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm1=newMyThread();//定义线程对象
- newThread(m1).start();//定义Thread对象
- newThread(m1).start();
- newThread(m1).start();
- }
- }
代码最终结果如下:
程序的问题:从运行结果中可以发现,程序中加入了延迟操作以后,票数会变为负数,出现这种情况的原因是:一个线程有可能在还没有对票数进行减操作之前,其它线程已经将票数减少了,这样一来就出现了票数为负的情况。
问题解决:如果想解决这种问题,就必须使用线程的同步操作,所谓的同步就是指多个操作在同一个时间段内只能有一个线程进行,其它线程要等待此线程完成之后才可以执行。
使用同步
要想解决资源共享的同步操作问题,可以使用同步代码块或者是同步方法两种方式完成。
同步代码块:
之前介绍了代码块分为四种:
1、 普通代码块:是直接定义在方法之中的。
2、 构造块:直接定义在类中,优先于构造方法执行,重复调用。
3、 静态块:使用static关键字声明:优先于构造块执行,只执行一次。
4、 同步代码块:使用synchronized关键字声明的代码块,成为同步代码块。
同步代码块格式:
- Synchronized(同步对象){
- 需要同步的代码;
- }
同步代码块必须指明同步的对象,一般情况下会将当前对象进行同步,使用this表示。
使用同步后的代码:
- classMyThreadimplementsRunnable{
- intticket=5;
- publicvoidrun(){
- synchronized(this){//同步代码块,同步当前对象
- for(inti=0;i<50;i++){
- if(ticket>0){
- try{
- Thread.sleep(300);
- }catch(InterruptedExceptione){
- e.getStackTrace();
- }
- System.out.println("卖票"+(ticket--));
- }
- }
- }
- }
- }
- publicclasssynchronizedDemo02
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm1=newMyThread();
- newThread(m1).start();
- newThread(m1).start();
- newThread(m1).start();
- }
- }
因为使用了方法的同步之后,在同一时间段内只能又一个线程执行,所以程序的执行效率会明显降低很多。
同步方法
除了可以将需要同步的代码设置成同步代码块之外,也可以使用synchronized关键字将一个方法声明成同步方法。
同步方法定义格式:
- snchronized方法返回值方法名称(参数列表){};
使用同步方法以后的代码:
- classMyThreadimplementsRunnable{
- intticket=5;
- publicvoidrun(){
- for(inti=0;i<50;i++){
- this.sale();//调用当前类中的同步方法
- }
- }
- publicsynchronizedvoidsale(){//同步方法
- if(ticket>0){
- try{
- Thread.sleep(300);
- }catch(InterruptedExceptione){
- e.getStackTrace();
- }
- System.out.println("卖票"+(ticket--));
- }
- }
- }
- publicclasssynchronizedDemo03
- {
- publicstaticvoidmain(Stringargs[]){
- MyThreadm1=newMyThread();
- newThread(m1).start();
- newThread(m1).start();
- newThread(m1).start();
- }
- }
死锁
1、 共享时需要进行同步操作
2、 程序中过多的同步会产生死锁。
扩展
方法定义的完整格式:
- 访问权限{public、default、protected、private}[final、static、synchronized]返回值类型方法名称(参数类型参数名称,…..)throwsExcption1,Exception2{
- rturn返回值(没有返回值则表示返回调用处);
- }
Object类对线程的支持---等待和唤醒
Object类是所有类的父类,在此类中又一下几个方法是对线程操作有所支持的。
线程的唤醒又两个方法:notify、notifyAll。一般来说,所有等待的线程会按照顺序进行排列,如果现在采用notify()方法,则会唤醒第一个等待的线程执行,而如果使用了notifyAll()方法,则会唤醒所有正在等待状态中得线程,哪个线程的优先级高,则就有可能执行。
线程的生命周期
一个新的线程被创建之后,通过start()方法进入到运行状态,在运行状态中可以使用yield()方法礼让,但是仍然可以进行,如果现在一个线程需要暂停,可是使用suspend()、sleep()、wait(),如果现在线程不需要再执行,则可以通过stop方法结束(如果run方法执行完毕也表示线程的结束),或者一个新的线程直接调用stop()方法也可以进行结束。
·suspend()方法:暂时挂起线程。
·resume()方法:恢复挂起的线程
·stop()方法:停止线程
因为以上方法会产生死锁的问题,所以很少使用,如果想停止一个线程,则可以使用一下委婉的方式:
- classMyThreadimplementsRunnable{
- privatebooleanflag=true;//定义标志位
- publicvoidrun(){
- inti=0;
- while(this.flag){
- System.out.println(Thread.currentThread().getName()
- +"运行,i="+(i++));
- }
- }
- publicvoidstop(){
- this.flag=false;//修改标志位
- }
- };
- publicclassStopDemo{
- publicstaticvoidmain(Stringargs[]){
- MyThreadmy=newMyThread();
- Threadt=newThread(my,"线程");//建立线程对象
- t.start();//启动线程
- try{
- Thread.sleep(30);
- }catch(Exceptione){
- }
- my.stop();//修改标志位,停止运行
- }
- };
- 转自:http://blog.csdn.net/cz1029648683/article/details/6655526
相关推荐
### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...
标题“多线程_按键精灵经典多线程操作_”表明我们将探讨的是如何在按键精灵这款自动化工具中实现多线程的功能。按键精灵是一款功能强大的自动化软件,它可以模拟用户的键盘和鼠标操作,执行一系列预定义的任务,如...
测试这个多线程互斥的例子,我们可以创建多个线程,每个线程分别调用`Increment`或`Decrement`方法,然后观察`GetValue`返回的值是否正确反映了操作的顺序。在`多线程test`这个项目中,很可能包含了这样的测试代码,...
在C#中,`System.Threading`命名空间提供了大量的类和方法来支持多线程编程,如`Thread`、`ThreadPool`、`Task`等。大漠的模板可能整合了这些工具,并进行了封装,使得开发者可以更方便地创建、管理和同步线程。 ...
在本案例中,介绍了一种使用委托的方法来安全地更新 UI 元素(特别是 ListBox 控件),以实现多线程操作。 #### 关键概念解析 **1. 多线程基础:** - **线程** 是程序执行流的基本单元,一个程序至少有一个线程...
尤其是在处理大量数据、并发操作或者需要进行IO等待时,多线程显得尤为重要。C#作为.NET框架的一部分,提供了丰富的多线程支持,使得开发者能够轻松地创建并管理多个线程。 在C#中,`System.Threading`命名空间是...
.NET框架的多线程技术是开发高性能应用程序的关键组成部分,特别是在处理并发操作、并行计算以及UI更新时。在.NET 2.0版本中,多线程功能已经得到了充分的优化和增强,允许开发者构建出更加高效的应用程序。下面将...
在多线程环境下使用`QsqlQuery`变量时,有时会遇到奇怪的问题,即使按照上述方法进行了处理,程序运行一段时间后仍可能出现数据库死锁或者异常关闭的情况。此时,可以尝试通过限制`QsqlQuery`变量的作用域来改善这一...
在标题"VB多线程操作"中,我们聚焦的是如何在VB中实现和管理多线程。 多线程在现代软件开发中的重要性不言而喻,尤其是在处理大数据、网络通信或UI更新等耗时操作时。VB支持通过Microsoft.VisualBasic.Threading...
多线程允许一个应用程序同时执行多个不同的任务,这在处理大量数据、实现并发操作或者优化用户体验时尤其有用。 "鱼刺框架"的稳定特性意味着它在设计时考虑了线程安全性和资源管理,确保在多线程环境下不会出现竞态...
在PB的早期版本中,多线程并不是原生支持的功能,因此开发者需要借助特定的控件或者方法来实现。 描述中提到的“原版本是pb11.5”,说明这个多线程解决方案最初是在PowerBuilder 11.5版本上开发的,后来被移植到了...
本科操作系统实验代码,使用多线程编程实现浮点向量的点积计算。
在.NET框架中,C#语言提供了强大的多线程支持,使得开发者可以充分利用现代多核处理器的优势,实现并行处理和高效能编程。本资源包含六个C#.NET多线程的实例,涵盖了多线程的基本使用到更高级的概念,如线程互斥。...
本文将深入探讨Java中的多线程操作方法,包括线程控制的基本方法、中断和睡眠以及相关示例。 首先,了解线程的基本状态至关重要。线程在运行过程中可能处于新建、可运行、运行、阻塞或死亡等状态。`isAlive()`方法...
多线程是一种提高程序运行效率和性能的常用技术。 随着我们学习工作的深入,在编程中或多或少会涉及到 需要多线程的情况。多数时候,我们的操作模式是后台 线程中处理数据,计算结果,然后在前台界面(GUI) 中更新...
### 可并行递归算法的递归多线程实现:深入解析 #### 引言:多线程与并行处理的重要性 随着计算任务日益复杂,传统的单线程编程模型已无法满足高效处理大规模数据的需求。多线程编程作为一种提高程序并发性和性能...
4. **线程安全**:如果一个方法或数据结构在多线程环境下能正确工作,我们就称其为线程安全。线程安全可以通过设计、同步机制或使用线程安全的数据结构来实现。 在实践中,多线程编程还需要关注性能和资源消耗,...
在计算机科学中,多线程是并发执行多个任务或子任务的一种方法,使得程序能够更高效地利用系统资源,特别是在多核处理器环境下,可以显著提高系统的吞吐量。 多线程技术的核心在于它能够让一个应用程序同时执行多个...
Qt5框架提供了一种方便的方式来实现多线程,它允许开发者在不同的线程中执行任务,从而避免主线程(GUI线程)因处理耗时操作而变得卡顿。本知识点将深入探讨Qt5中的多线程以及一个简单的实例——WorkThread。 **1. ...
1. **多线程编程**:C#中的`System.Threading`命名空间提供了丰富的类和方法来创建和管理线程,如`Thread`类、`Task`类以及`ThreadPool`。通过多线程,程序可以同时执行多个任务,但这也可能导致数据冲突。 2. **...