java

位置:IT落伍者 >> java >> 浏览文章

Java多线程程序设计入门


发布日期:2021年11月24日
 
Java多线程程序设计入门

在Java语言产生前传统的程序设计语言的程序同一时刻只能单任务操作效率非常低例如程序往往在接收数据输入时发生阻塞只有等到程序获得数据后才能继续运行 随着Internet的迅猛发展这种状况越来越不能让人们忍受如果网络接收数据阻塞后台程序就处于等待状态而不继续任何操作而这种阻塞是经常会碰到的此时CPU资源被白白的闲置起来如果在后台程序中能够同时处理多个任务该多好啊!应Internet技术而生的Java语言解决了这个问题多线程程序是Java语言的一个很重要的特点在一个Java程序中我们可以同时并行运行多个相对独立的线程例如我们如果创建一个线程来进行数据输入输出而创建另一个线程在后台进行其它的数据处理如果输入输出线程在接收数据时阻塞而处理数据的线程仍然在运行多线程程序设计大大提高了程序执行效率和处理能力

线程的创建

我们知道Java是面向对象的程序语言用Java进行程序设计就是设计和使用类Java为我们提供了线程类Thread来创建线程创建线程与创建普通的类的对象的操作是一样的而线程就是Thread类或其子类的实例对象下面是一个创建启动一个线程的语句

Thread thread=new Thread(); file://声明一个对象实例即创建一个线程

Threadrun(); 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()

{

Systemoutprintln(Thread is running…);

}

}

file://通过Runnable接口创建的另外一个线程

class thread implements Runnable

{

file://自定义线程的run()方法

public void run()

{

Systemoutprintln(Thread is running…);

}

}

file://程序的主类

class Multi_Thread file://声明主类

{

plubic static void mail(String args[]) file://声明主方法

{

thread threadone=new thread(); file://用Thread类的子类创建线程

Thread threadtwo=new Thread(new thread()); file://用Runnable接口类的对象创建线程

threadonestart(); threadtwostart(); file://strat()方法启动线程

}

}

运行该程序就可以看出线程threadone和threadtwo交替占用CPU处于并行运行状态可以看出启动线程的run()方法是通过调用线程的start()方法来实现的(见上例中主类)调用start()方法启动线程的run()方法不同于一般的调用方法调用一般方法时必须等到一般方法执行完毕才能够返回start()方法而启动线程的run()方法后start()告诉系统该线程准备就绪可以启动run()方法后就返回start()方法执行调用start()方法语句下面的语句这时run()方法可能还在运行这样线程的启动和运行并行进行实现了多任务操作

线程的优先级

对于多线程程序每个线程的重要程度是不尽相同如多个线程在等待获得CPU时间时往往我们需要优先级高的线程优先抢占到CPU时间得以执行又如多个线程交替执行时优先级决定了级别高的线程得到CPU的次数多一些且时间多长一些这样高优先级的线程处理的任务效率就高一些

Java中线程的优先级从低到高以整数~表示共分为设置优先级是通过调用线程对象的setPriority()方法如上例中设置优先级的语句为

thread threadone=new thread(); file://用Thread类的子类创建线程

Thread threadtwo=new Thread(new thread()); file://用Runnable接口类的对象创建线程

threadonesetPriority(); file://设置threadone的优先级

threadtwosetPriority(); file://设置threadtwo的优先级

threadonestart(); threadtwostart(); file://strat()方法启动线程

这样线程threadone将会优先于线程threadtwo执行并将占有更多的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()从仓库中取走产品模拟销售者另外一个线程类producer中的run()方法通过调用仓库类中的store_in()方法向仓库添加产品模拟产品制造者在主类中创建并启动线程实现向仓库中添加产品或取走产品

如果仓库类中的store_in() 和store_out()方法不声明同步这就是个一般的多线程我们知道一个程序中的多线程是交替执行的运行也是无序的这样就可能存在这样的问题

仓库中没有产品了销售者还在不断光顾而且还不停的在产品这在现实中是不可思义的在程序中就表现为负值如果将仓库类中的stroe_in()和store_out()方法声明同步如上例所示就控制了同一时刻只能有一个线程访问仓库对象中的同步方法即一个生产类线程访问被声明为同步的store_in()方法时其它线程将不能够访问对象中的store_out()同步方法当然也不能访问store_in()方法必须等到该线程调用wait()方法放弃钥匙其它线程才有机会访问同步方法

这个原理实际中也很好理解当生产者(producer)取得仓库唯一的钥匙就向仓库中添放产品此时其它的销售者(customer可以是一个或多个)不可能取得钥匙只有当生产者添放产品结束交还钥匙并且通知销售者不同的销售者根据取得钥匙的先后与否决定是否可以进入仓库中提走产品

               

上一篇:Java多线程编程三步曲[1]

下一篇:Java开发下的设计模式简单说明