多线程

来源:互联网 发布:皇室战争大雷电数据 编辑:程序博客网 时间:2024/05/16 13:33

 

2012/4/23

Overview

了解程序、进程与线程的区别

掌握Java线程的两种实现方式

了解线程的操作状态

线程的同步与死锁

1、程序、进程与线程

程序是计算机指令的集合,它以文件的形式存储在磁盘上。

进程:是一个程序在其自身的地址空间中的一次执行活动

进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源。

程序、进程与线程

线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。

线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。

单线程程序与多线程程序

Java运行环境——单进程多线程

多线程的目的是为了最大限度的利用CPU资源。

Java编写程序都运行在在JVM中,在JVM的内部,程序的多任务是通过线程来实现的。启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。

2Java线程的两种实现方式

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=newMyThread(“线程A”);

            MyTHread mt2=newMythread(“线程B”);

            mt1.run();   //调用线程主体。

            mt2.run();

      }

}

线程类的使用误区:

直接调用线程run方法,并不会让一个线程启动,其效果实际上与一般的方法调用一样,只是在主线程中执行。

让一个线程启动的正确方法是使用Thread类定义中的start()方法。

线程子类应用示例

public classThreadDemo1{

      public static void main(String args[]){

            MyThread mt1=newMyThread(“线程A”);

            MyTHread mt2=newMythread(“线程B”);

            mt1.start();  

            mt2.start();

      }

}

线程调度

调度的方式分为:分时调度,抢占式调度

java虚拟机是抢占式调度,在java编程中,抢占式调度是指根据优先级来获得CPU的分配使用,如果同级则是根据随机选择。

Runnable接口

通过实现Runnable接口的方式来实现多线程,Runnable接口中只定义了一个抽象方法:

}publicvoid run();

通过Runnable接口实现多线程:

class 类名 implements Runnable{

      //属性;

      //方法;  

      //覆写Runnable接口的run()方法

      public void run(){ ……} //线程主体

}

Runnable接口使用示例

Class MyThread implementsRunnable{

      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= newMyThread(“线程A”);

        MyThread mt2 = newMyThread(“线程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接口实现的多线程操作可以实现资源共享。

RunnableThread类的优点:

适合多个相同程序代码的线程去处理同一个资源;

可以避免由于单继承局限所带来的影响

增强了程序的健壮性,代码能够被多个线程共享

线程的状态

多线程在操作中也是有一个固定的操作状态:

创建状态:准备好了一个多线程对象:Thread= new Thread();

就绪状态:调用了start()方法,等待CPU进行调度

运行状态:执行run()方法

阻塞状态:暂时停止执行,可能将资源交给其他线程使用

终止状态(死亡状态):线程执行完毕,不再使用。

线程状态图

线程的同步与死锁

什么时候需要线程同步?

火车票出售,将不同的售票点当成不同的线程,那这些线程都共享同一份数据——火车票。A售票点工作人员查询系统,目前还有1张票,准备出售时,有急事离开一会,此时,B售票点工作人员查询系统,还有1张票,出票,A工作人员回来后,再出售车票,此时票数不对了。

资源共享的问题——示例

Class MyThread implementsRunnable{

      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 = newMyThread();

     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 havegived 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