Java中的多线程编程

20 篇文章 0 订阅

转帖自 http://www.cnblogs.com/baoguo/articles/826534.html

Java中的多线程编程

 

Java中的多线程编程

主要内容

初识Java多线程

线程的生命周期

Java多线程程序设计方法

多线程应用示例

线程的优先级、同步*

 

初识多线程

一个简单的多线程的示例

class ManyThread extends Thread{

  int n=0;

 

  public static void main(String[] aa){

     ManyThread t1=new ManyThread();

     ManyThread t2=new ManyThread();

     System.out.println("Thread1 start!");

     t1.start();

     System.out.println("Thread2 start!");

     t2.start();

     System.out.println("Ok");

  }

  public void run(){

     while(n<10){

        n++;

      System.out.println(currentThread().getName()+"/t"+n);

     }

  }

}

结论:

²       线程类名为Thread,可由Thread及其子类创建线程对象。

²       可通过Thread.currentThread()可测得当前线程

²       线程是由start启动的,启动后会自动执行run方法。

 

单线程和多线程

线程:一个程序中彼此分离的、能独立运行的子任务。

单线程和排队等候

没有特意创建线程的程序为单线程程序, Java能自动创建和控制线程。

单线程的本质是排队等候,一个任务必须在另一个任务之后执行。

资源利用率低,CPU在大多时候空闲

 

多线程和并行执行

多线程的程序将任务分成几个子任务,多个子任务并行操作。(抢占式)

 

 

思考

1.    多线程程序的运行方式是?

2.    一个任务运行完毕,再执行另一个任务,这是单线程还是多线程?

3.    多线程的程序有什么优越之处?

4.    哪种程序有更好的用户响应能力?

5.    线程是如何启动的?

6.    线程启动后具体执行的方法是?

7.    在多线程工作时,怎么测得当前占据CPU运行时刻的线程?

 

线程的生命周期

在一个线程的生命周期中,它总处于某一种状态中。

Thread类及其主要方法

构造方法

public Thread()用缺省名称创建一个Thread对象

public Thread(String name)用指定名称创建一个Thread对象

 

线程的常用方法

说明

任务

public void start()

启动一个线程

public void run()

执行线程

 

休眠

public void stop()

停止线程

public static Thread currentThread()

必须throws InterruptedException

返回当前线程

public String getName()

返回线程的名称

 

线程的状态

线程的状态通常可归纳为:新生态运行态不可运行态死亡态四种状态。

新生态

时机:当创建了类Thread或其子类的实例对象时,一个新的线程就产生了。

ManyThread t1=new ManyThread()

线程去向:只能启动或终止该线程。调用start()stop()之外的其它方法都会失败并且会引起非法状态处理。

 

运行态( Runnable )

时机:对新生态的线程执行start()方法进入运行态,此时该线程处于可运行状态。

t1.start();

线程去向:进入不可运行的状态(等待或睡眠)和死亡态。

说明

²       处于运行态的线程都在运行或侍机运行。

²       单处理器的计算机,每一时刻真正处于运行中的线程只有一个。

²       JavaVM实现调度来保证这些线程共享处理器。

 

不可运行态

时机:对运行态中的线程进行了如下处理后,线程处于不可运行状态。

²       调用了sleep()方法;

²       调用了suspend()方法(线程被挂起)

²       为等候一个条件变量,线程调用wait()方法;

²       输入输出流中发生线程阻塞。

try {

Thread.currentThread().sleep(10000);

} catch (InterruptedException e){}

线程去向:进入运行态或死亡态。

 

四种不可运行态有不同的方式回到运行态

sleep()——方法中的参数为睡眠时间,时间一到,线程即为可运行的;

suspend()——调用resume()方法来返回;

wait()——该条件变量所在的对象调用notify()notifyAll()方法;

I/O流中发生线程阻塞——待特定的I/O指令结束,自动回到可运行态。

 

死亡态

时机:对线程执行stop()方法,或线程运行结束,即进入死亡态。

说明:可用线程对象=null;代替线程对象.stop();

 

多线程程序设计

Thread继承类创建线程

程序框架

class NewThread extends Thread{ //对应一个任务

  ……

  public void run(){

 

  }

}

  ……

class ThreadTest{

  public static void main(String[] aa){

     NewThread t=new NewThread();

     t.start();

  ……

  }

}

要点:

²       定义一个继承Thread的子类,重写 run()方法,实现一个子任务。

²       main方法中,实例化子类,创建一个线程对象,并调用start()方法执行子任务。

 

例:阅读和分析程序。

class ThreadTest extends Thread{

  int n=0;

  int count=0;

  ThreadTest(int i){

     count=i;

     start();

  }

  public void run(){

     while(true){

        System.out.print(count+" ");

        if(n++>15)return;

//       yield();

     }

  }

  public static void main(String[] aa){

     for(int i=0;i<5;i++)

        new ThreadTest(i);

  }

}

 

得到结论:

²       主线程的执行位置就是main

²       每个线程执行其代码的方式都是顺序执行的。

²       一个线程执行其代码与其他线程相互独立。

 

进一步的理解:

²       线程对于cpu时间片的交替占有特性。

²       yield()方法,让当前线程作出让步。

public static void yield()

²       sleep()可让线程休眠一定的时刻毫秒数

public static void sleep(long millis)

分析和回答

 

1.    程序启动了多少个线程?

2.    线程的执行机会是顺序均匀的吗?

3.    让线程作出让步的方法是?

4.    让线程休眠的方法是?

5.    哪条语句决定一个线程运行结束?

6.    ThreadTest的构造方法中执行start意在?

 

Runnable接口创建线程

Runnable接口继承自Thread,其中只有一个run()方法。

察看Thread的其他构造方法

public  Thread(Runnable target)

public  Thread(Runnable target,String name)

通过Runnable创建线程的步骤:

²       定义一个实现了Runnable的类,其中重写run方法说明任务。

²       通过new Thread(Runnable子类的实例对象)创建线程。

 

练习1:利用Runable改写上例。

 

练习2:用多线程模拟多处卖票的问题(假定总共有100张票,有三个卖票窗口)。

class SellTicket implements Runnable{

  static int num=1;

  public void run(){

 

  }

  public static void main(String[] aa){

 

  }

}

比较:多线程设计时,Runnable接口更具灵活性。一个用户类可以在继承别的类的基础上实现该接口。

思考

1.    程序启动了多少个线程?

2.    线程的执行机会是顺序均匀的吗?

3.    让线程作出让步的方法是?

4.    让线程休眠的方法是?

5.    哪条语句决定一个线程运行结束?

6.    ThreadTest的构造方法中执行start意在?

 

多线程应用举例

一个时钟Applet示例

设计如下图示的时钟,可以逐秒更新显示。

 

设计分析

Clock继承JApplet,并实现Runnable接口,通过一个线程来实现时间的更新显示。

其中各方法的主要任务:

init()——

paint(Graphics g) ——获取当前日历,显示时间

run()——线程的运行(隔一秒刷新)

 

取得系统时间的方法:

Calendar now = Calendar.getInstance();

利用其中的get方法获取HOURMINUNTSECOND

import java.awt.*;

import java.util.*;

import javax.swing.*;

 

public class Click extends JApplet implements Runnable{

  Font f=new Font("",0,50);

  public void init(){

  //创建并运行线程

  }

  public void paint(Graphics g){

     g.clearRect(0,0,this.getWidth(),this.getHeight());

     g.setFont(f);

     g.setColor(Color.green);

     g.drawString(getTime(),50,50);

  }

  public void run(){

  //线程的运行(隔一秒刷新)

  }

  public String getTime(){

     Calendar now=Calendar.getInstance();

     //取得系统时间

  }

}

 

练习:将上例改写为Java Application

 

一个飞行动画Applet

飞船图片文件名:Rocketship.gif

 

线程的优先级和线程调度

CPU的计算机在执行多线程程序时需进行线程调度。

线程优先级的设置

public final void setPriority(int newPriority)

参数:可选线程中的三个静态变量

²       MAX_PRIORITY(高优先级)10

²       MIN_PRIORITY(低优先级)1

²       NORM_PRIORITY(缺省的优先级)5

Java采用的是抢占式的调度方式,高优先级的线程进入可运行(runnable)状态时,会抢占低优先级的线程的位置。

 

例:观察下列程序的执行情况,回答问题。

class ThreadTest{

  public static void main(String[] aa){

     MyThread mt1=new MyThread();

     MyThread mt2=new MyThread();

     mt1.setPriority(5);

     mt2.setPriority(10);

     mt1.start();

     mt2.start();

     while(true){

        System.out.println(Thread.currentThread().getName());

     }    

  }

}

class MyThread extends Thread{

  public void run(){

     while(true){

        System.out.println(this.getName());

     }    

  }

}

问题

高优先级线程会绝对占据CPU资源吗?

观察程序运行结果,体会线程优先级的意义

 

线程的同步

以上所创建和运行的线程都是独立的,而且异步执行:

²       每个线程自含了运行所需要的数据或方法,不需要外部的资源或方法

²       每个线程不关心其它线程的状态或行为。

 

为什么要同步?

问题:有两个线程thread1thread2,当它们操作同一个对象时,会发现由于thread1thread2是同时执行的,因此可能thread1修改了数据而thread2读出的仍为旧数据。

问题原因:资源使用协调不当(不同步)造成的。

解决方法:协调线程,以免共享资源时,线程间发生冲突。——同步

同步的实现方法

Java提供了同步方法和同步状态来协调资源:

²       同步方法指方法前修饰synchronized关键字

²       同步状态指对象或数据前修饰synchronized关键字

²       被宣布为同步的方法、对象或类数据,在任一时刻只能被一个线程使用

 

同步方法

同步方法:用synchronized修饰的方法

作用:同步方法当一个线程执行时自动加锁,直到方法运行结束锁解除。

例:阅读程序,理解同步方法

class SynchTest implements Runnable{

  public static void main(String args[]){

     SynchTest st=new SynchTest();

     Thread t1=new Thread(st);

     Thread t2=new Thread(st);

     t1.start();

     t2.start();

     while((t1.isAlive())||(t2.isAlive()));

     System.out.println("The test is end.");

  }

  public void run(){

     String name=Thread.currentThread().getName();

     show(name);

     System.out.println(name+" is dead!");

  }

  private  synchronized  void show(String name){

     for(int j=1;j<=10;j++){

        System.out.println("I am "+name+"-- I have run "+j+" times.");

     }

  }

}

 

关键字synchronized会告诉JVM在方法运行时需要一个锁,然后 JVM会创建并管理锁:

²       线程可自动请求锁

²       除非某个线程已经申请并获准使用锁,否则很容易申请到锁

²       当同步方法结束后会自动释放锁

 

同步块

同步块:用synchronized(Object)标识的语句块。

作用:语句块被一个线程执行时会自动加锁,直到运行结束,锁解除。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值