Presentation is loading. Please wait.

Presentation is loading. Please wait.

第22讲 Java高级编程(一).

Similar presentations


Presentation on theme: "第22讲 Java高级编程(一)."— Presentation transcript:

1 第22讲 Java高级编程(一)

2 教学目标 理解多线程程序设计的基本思想 掌握多线程的实现和线程的同步与控制 理解Java网络编程的基本思想
掌握基于Socket的低层Java网络编程与基于UDP的Java网络编程,以及基于无连接的数据报通信编程 理解JDBC的基本思想 掌握数据源的建立和数据库的访问

3 多线程程序设计 支持多线程——Java可以让不同的程序块同时运行,可以达到处理多任务的目的。
所谓的线程(thread)是指程序的运行流程,多线程的技术使单个程序内部也可以在同一时刻执行多个代码段,完成不同的任务,这种机制称为多线程。 Java语言利用多线程实现了一个异步的执行环境。例如,在一个网络应用程序里,可以在后台运行一个下载网络数据的线程,在前台则运行一个线程来显示当前下载的进度,以及一个用于处理用户输入数据的线程。 Java多线程机制是通过Java类包java.lang中的类Thread实现的,Thread类封装了对线程控制所必需的方法。

4 单线程实现示例 class ST extends Thread{ public ST(String str){ super(str); }
public void run() { String B[] = {"起床","早饭","上班","下班"}; String S[] = {"备课","上课","布置作业","下课"}; String Name = null; Name = getName(); for(int i = 0;i<4;i++) { if(Name.equals("B")){ System.out.println(Name+":"+B[i]); try{ sleep((long)(Math.random()*1000)); }catch(InterruptedException e){} } if(Name.equals("S")){ System.out.println(Name+":"+S[i]); try { sleep((long)(Math.random()*1000)); } } }} 单线程实现示例

5 单线程实现示例(续) 运行结果: B:早饭 B:上班 B:下班 S:备课 S:上课 S:布置作业 S:下课
public class Ex12_1 { public static void main(String args[]) ST s1 = new ST("B"); ST s2 = new ST("S"); s1.run(); s2.run(); } 程序分析: try块中sleep()方法只是简单地告诉线程休息多少毫秒,其参数为休息时间。当这个时间过去后,线程即可继续执行。当某个线程睡眠时,sleep()并不占用系统资源,其他某一线程可继续工作。

6 多线程的实现 单线程的限制——要运行s2.run()方法,一定要等到s1.run()运行完毕才行。
实现多线程的方法: 在类里激活线程 此类必须是扩展自Thread类,extends Thread 线程的处理必须编写在run()方法内。 run()方法是定义在Thread类中的一个方法。 使用接口实现多线程

7 多线程实现示例 class ST extends Thread{ public ST(String str) { super(str); }
public void run() { String B[] = {"起床","早饭","上班","下班"}; String S[] = {"备课","上课","布置作业","下课"}; String Name = null; Name = getName(); for(int i = 0;i<4;i++) { if(Name.equals("B")) { System.out.println(Name+":"+B[i]); try { sleep((long)(Math.random()*1000)); }catch(InterruptedException e){} } if(Name.equals("S")) { System.out.println(Name+":"+S[i]); try { sleep((long)(Math.random()*1000)); } } }} 多线程实现示例

8 多线程实现示例(续) public class Ex12_2{
public static void main(String args[]) { new ST("B").start(); new ST("S").start(); } 运行结果: 第一次运行 第二次运行 第三次运行 B:起床 B:起床 B:起床 S:备课 S:备课 S:备课 S:上课 B:早饭 S:上课 S:布置作业 S:上课 B:早饭 B:早饭 B:上班 B:上班 S:下课 S:布置作业 B:下班 B:上班 B:下班 S:布置作业 S:下班 S:下课 S:下课 程序分析: 程序中的main()方法中构 造了两个ST类的线程,一个称 为“B”线程“,另一个称为“S”线 程,并调用了start()方法来启 动这两个线程。这两个线程同时运行,并且同时显示输出,且这两个线程的输出次序是随机的。

9 使用接口实现多线程 如果类本身已经继承了某个父类,现在又要继承Thread类来创建线程,就违背了Java不支持多继承的原则,解决这个问题的方法是使用接口。 实现接口Runnable。Runnable接口里声明了抽象的run() 方法,把处理线程的程序代码放在run()里就可以创建线程了。 创建一个程序实现当前时间显示,要求每2秒显示1次,显示20次后程序退出。 分析:在Java的java.util包中有一个Date类,可以通过实例化一个Date对象得到当前时间。要求每两秒显示一次时间,线程是完成这个任务最好的角色。通过每两秒唤醒线程一次,并且就在这一瞬间显示出时间。还需设置一个循环控制输出次数。

10 使用接口实现多线程示例 import java.util.Date;
public class Ex12_3 implements Runnable{ private Thread clock = null ;private Date nowtime = new Date(); public Ex12_3(){clock = new Thread(this);clock.start();} public void run(){ while(true){ nowtime = new Date(); System.out.println(nowtime); try{clock.sleep(2000); } catch(InterruptedException ie) {System.err.println("Thread error: " + ie);} } public static void main(String args[]){ Ex12_3 time = new Ex12_3();

11 使用接口实现多线程示例(续) 运行结果: Sat Feb 10 10:51:37 CST Sat Feb 10 10:51:39 CST 2007 Sat Feb 10 10:51:41 CST Sat Feb 10 10:51:43 CST 2007 Sat Feb 10 10:51:45 CST Sat Feb 10 10:51:47 CST 2007 Sat Feb 10 10:51:49 CST Sat Feb 10 10:51:51 CST 2007 Sat Feb 10 10:51:53 CST Sat Feb 10 10:51:55 CST 2007 Sat Feb 10 10:51:57 CST Sat Feb 10 10:51:59 CST 2007 Sat Feb 10 10:52:01 CST Sat Feb 10 10:52:03 CST 2007 Sat Feb 10 10:52:05 CST Sat Feb 10 10:52:07 CST 2007 Sat Feb 10 10:52:09 CST Sat Feb 10 10:52:11 CST 2007 Sat Feb 10 10:52:13 CST Sat Feb 10 10:52:15 CST 2007 程序分析: 通过Thread类的构造方法创建clock线程并进行初始化,同时将Ex12_3类的当前对象(this)作为参数。该参数将clock线程的run()方法与Ex12_3类实现runnable接口的run()方法联系在一起,因此,当线程启动后,Java类的run()方法就开始执行。

12 多线程同步示例 运行结果: sum=100 sum=200 sum=300 public class Ex12_4{
public static void main(String args[]) { Cperson c1 = new Cperson(); Cperson c2 = new Cperson(); c1.start(); c2.start(); } } class Countmoney { private static int sum=0; public static void add(int n) { int t = sum; t = t + n; try{ Thread.sleep((int)(1000*Math.random()));} catch(InterruptedException e){} sum = t; System.out.println("sum="+sum); }} class Cperson extends Thread{ public void run() { for(int i = 1;i<=3;i++) Countmoney.add(100); 运行结果: sum=100 sum=200 sum=300

13 多线程同步示例 程序分析: 输出结果不正确。其错误原因在于两个线程在各自run()方法还没结束前,另一个线程已开始激活,因此造成计算上的错误。 要更正这个错误,只要设置c1线程处理完之后,接着处理c2线程就可以了。在aad()方法之前加上synchronized关键字,使其成为同步方法。 public synchronized static void add(int n){…… } class Cperson extends Thread { public void run() { for(int i = 1;i<=3;i++) Countmoney.add(100); }

14 实现多线程同步 ——synchronized
为了避免资源冲突,Java使用关键字synchronized使方法通信同步,在同一时间内,一个方法只能有一个线程运行。 在本例中,可以学到同步处理的重要性。如有多个线程共享一个变量时,特别要注意它们之间的访问顺序,否则一个线程未处理完某个方法时,另一个线程又进来,就有可能发生错误。

15 线程的四种状态 每一个线程,一般有四种状态:创建、运行、阻塞与消亡。这四种状态均可通过Thread类所提供的方法来控制。线程状态的转移与方法之间的关系如图12-1所示。 线程在产生时便进入创建状态。即new Thread()创建对象时,线程所处的便是这个状态,但此时系统并不会分配资源,直到用start()方法激活线程时才会分配。 当start()方法激活线程时,线程进入可运行的状态。此时最先抢到CPU资源的线程先开始运行start()方法,其余的线程在队列中等待机会争取CPU的资源,一旦争取到就开始运行。

16 线程状态转换图 图12-1 线程状态的转移与方法之间的关系

17 线程的四种状态的转换过程 当发生下列事件之一时,线程就进入阻塞状态。
1.该线程调用对象的wait()方法; 2.该线程本身调用sleep()方法。sleep(long millis)可用来设置睡眠的时间。 3.该线程和另一个线程join()在一起时。当某一线程调用join()时,则其他尚未激活的线程或程序代码会等到该线程结束后才会开始运行。 当线程被阻塞后,便停止run()方法的运行,直到被阻塞的原因不存在后,线程回到可运行状态,继续排队争取CPU的资源。

18 线程的状态转换 线程被阻塞情形消失的原因有下列几点:
1.如果线程是由调用对象的wait()方法所阻塞,则该对象的notify()方法被调用时可解除阻塞。notify()方法用来“通知”被wait()阻塞的线程开始运行。 2.线程进入睡眠状态,但指定的睡眠时间到了。 当线程的run()方法结束,或是线程调用它的stop()时,则线程进入消亡的状态。 利用上述方法可以完成线程间的通信以及线程状态之间的转换,下面举例说明通过wait()、notify()来达到线程间的通信和状态的转换。

19 线程间通信示例 例12_5 线程间通信的示例。本例模拟两个银行之间的转帐业务,当A银行转帐给B银行后,暂停转帐,通知B银行转帐给A银行,转帐金额随机确定,源代码如下。 import java.awt.*; import java.awt.event.*; public class Ex12_5 extends Frame { protected static final String[] NAMES = {"A","B"}; private int accounts[] = {1000,1000}; private TextArea info = new TextArea(5,40); private TextArea status = new TextArea(5,40);

20 线程间通信示例(续) public Ex12_5(){
super("Ex12_5");setLayout(new GridLayout(2,1)); add(makePanel(info,"Accounts")); add(makePanel(status,"Threads")); validate();pack();setVisible(true); Ex12_5Thread A = new Ex12_5Thread(0,this,status); Ex12_5Thread B = new Ex12_5Thread(1,this,status); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent we) {System.exit(0);} });}

21 线程间通信示例(续) public synchronized void transfer(int from,int into,int amount){ info.append("\nAccount A: $" + accounts[0]); info.append("\tAccount B: $" + accounts[1]); info.append("\n=> $" + amount + " from " + NAMES[from] + " to " + NAMES[into]); while(accounts[from] < amount){ try{wait();}catch(InterruptedException ie){System.err.println("Error: " + ie);} } accounts[from] -= amount;accounts[into] +=amount;notify(); private Panel makePanel(TextArea text,String title){ Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add("North",newLabel(title)); p.add("Center",text);return p; public static void main(String args[]){ Ex12_5 bank = new Ex12_5(); }} public static void main(String args[]) {Ex12_5 bank = new Ex12_5();}

22 线程间通信示例(续) class Ex12_5Thread extends Thread{ private Ex12_5 bank;
private int id; private TextArea display; public Ex12_5Thread(int _id,Ex12_5 _bank,TextArea _display){ bank = _bank;id = _id;display = _display;start(); } public void run(){ while(true){int amount = (int)(900*Math.random()); display.append("\nThread " + Ex12_5.NAMES[id] + " sends $ " + amount + " into " + Ex12_5.NAMES[(1-id)]); try{sleep(50); }catch(InterruptedException ie){ System.err.println("Interrupted"); bank.transfer(id,1-id,amount);

23 线程间通信示例(续) 图12-1 运行结果 程序分析:
程序中创建一个银行类Ex12_5,一个整型数组域accounts[]给两个银行初始化银行账户金额,然后在其构造方法中创建两个银行客户线程A和B。这个程序中最重要的方法是transfer(),它是同步方法。它需要三个参数:取钱的账号,存钱的账号,转帐的金额。在转帐之前检查相应账号是否有足够的资金,然后在转帐之后计算新的余额。这个方法被每个银行共享,因此必须设计为同步方法,在一个银行使用时,这个方法被加锁,不再使用时,自动解锁,其他银行可以使用这个方法。 程序中使用了方法start()、sleep()、run()、notify()和wait(),请分析它们在程序中的作用,并理解运行顺序。 如果将上例中int amount = (int)(900*Math.random());中900换成1500后运行结果会怎样? 图12-1 运行结果


Download ppt "第22讲 Java高级编程(一)."

Similar presentations


Ads by Google