2012/4/23
Overview
了解程序、进程与线程的区别
掌握Java线程的两种实现方式
了解线程的操作状态
线程的同步与死锁
1、程序、进程与线程
程序是计算机指令的集合,它以文件的形式存储在磁盘上。
进程:是一个程序在其自身的地址空间中的一次执行活动
进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源。
程序、进程与线程
线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。
线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
单线程程序与多线程程序
Java运行环境——单进程多线程
多线程的目的是为了最大限度的利用CPU资源。
Java编写程序都运行在在JVM中,在JVM的内部,程序的多任务是通过线程来实现的。启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。
2、Java线程的两种实现方式
Java在语言级提供了对多线程程序设计的支持。
实现多线程程序的两种方式:
(1)从Thread类继承;
(2)实现Runnable接口。
继承Thread类
Thread类定义在java.lang包中,一个类只要继承了Thread类,此类就称为多线程操作类。在Thread子类中,必须明确的覆写Thread类中的run()方法,此方法为线程的主体。
多线程定义语法
class 类名 extends Thread{
//属性;
//方法;
//覆写Thread类中的run()方法,此方法是线程的文体
Public void run(){
//线程文体。
}
}
线程子类应用示例
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(inti=0; i<10; i++){
System.out.println(name +”运行:”+i);
}
}
}
线程子类应用示例
public classThreadDemo1{
public static void main(String args[]){
MyThread mt1=new MyThread(“线程A”);
MyTHread mt2=new Mythread(“线程B”);
mt1.run(); //调用线程主体。
mt2.run();
}
}
线程类的使用误区:
直接调用线程run方法,并不会让一个线程启动,其效果实际上与一般的方法调用一样,只是在主线程中执行。
让一个线程启动的正确方法是使用Thread类定义中的start()方法。
线程子类应用示例
public classThreadDemo1{
public static void main(String args[]){
MyThread mt1=new MyThread(“线程A”);
MyTHread mt2=new Mythread(“线程B”);
mt1.start();
mt2.start();
}
}
线程调度
调度的方式分为:分时调度,抢占式调度
java虚拟机是抢占式调度,在java编程中,抢占式调度是指根据优先级来获得CPU的分配使用,如果同级则是根据随机选择。
Runnable接口
通过实现Runnable接口的方式来实现多线程,Runnable接口中只定义了一个抽象方法:
通过Runnable接口实现多线程:
class 类名 implements Runnable{
//属性;
//方法;
//覆写Runnable接口的run()方法
public void run(){ ……} //线程主体
}
Runnable接口使用示例
Class MyThread implements Runnable{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(inti=0;i<10;i++){
System.out.println(name+”运行:”+i);
}
}
}
Runnable接口使用示例
public class RunnableDemo{
MyThread mt1= new MyThread(“线程A”);
MyThread mt2 = new MyThread(“线程B”);
Thread t1 = new Thread(mt1);
Thread t2 = new Thread(mt2);
//t1.run();
t1.start();
t2.start();
}
Thread类与Runnable接口
Thread类与Runnable接口的联系
Thread类的定义
public class Threadextends Object implements Runnable{
public Thread(Runnable){
init(null, target, name, 0);
}
private void init(…, Runnable target,…){
……
this.target = target;
}
public void run(){
target.run();
}
}
Thread类与Runnable接口的区别
使用Thread类在操作多线程的时时候无法达到资源共享的目的,而使用Runnable接口实现的多线程操作可以实现资源共享。
Runnable较Thread类的优点:
适合多个相同程序代码的线程去处理同一个资源;
可以避免由于单继承局限所带来的影响
增强了程序的健壮性,代码能够被多个线程共享
线程的状态
多线程在操作中也是有一个固定的操作状态:
创建状态:准备好了一个多线程对象:Thread= new Thread();
就绪状态:调用了start()方法,等待CPU进行调度
运行状态:执行run()方法
阻塞状态:暂时停止执行,可能将资源交给其他线程使用
终止状态(死亡状态):线程执行完毕,不再使用。
线程状态图
线程的同步与死锁
什么时候需要线程同步?
火车票出售,将不同的售票点当成不同的线程,那这些线程都共享同一份数据——火车票。A售票点工作人员查询系统,目前还有1张票,准备出售时,有急事离开一会,此时,B售票点工作人员查询系统,还有1张票,出票,A工作人员回来后,再出售车票,此时票数不对了。
资源共享的问题——示例
Class MyThread implements Runnable{
private int ticket = 5;
public void run(){
for(inti=0; i<100; i++){
if(ticket>0){
try{
Thread.sleep(300);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(“票数:”+ticket--);
}
}
}
}
资源共享的问题——示例
Public class TestDemo{
MyThreadmt = new MyThread();
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
t1.start();
t2.start();
t3.start();
}
如何进行线程同步
解决资源共享的同步操作问题,有两种方式:
同步代码块
同步方法
同步代码块格式:
synchronized(同步对象){
// 需要同步的代码;
}
同步的时候必须指明同步的对象,一般情况下会将当前对象作为同步对象,用this变量引用。
如何进行线程同步
同步方法:
除了可以将需要的代码进行同步之外,也可以将一个方法声明为同步方法。
同步方法定义格式:
syschronized方法返回类型 方法名(参数列表){
//方法体
}
线程死锁
资源共享时需要进行同步操作。
程序中过多的同步可能产生死锁。
死锁
商店规定,先给钱再送货,顾客要示,先送货再给钱。商店与顾客将互相等待。
死锁——示例
public class TestDeadlock {
static class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void get(Personper) {
System.out.format("%s: want to get from %s%n",
this.name, per.getName());
per.give(this);
}
public synchronized void give(Personper) {
System.out.println("I have gived out");
}
}
死锁——示例
public static void main(String[] args) {
final Person A = newPerson("A");
final Person B = newPerson("B");
new Thread(new Runnable() {
public void run() { A.get(B); }
}).start();
new Thread(new Runnable() {
public void run() { B.get(A); }
}).start();
}
}
Thanks!