黑马程序员__多线程

来源:互联网 发布:欧洲人 野蛮 知乎 编辑:程序博客网 时间:2024/04/28 15:43

黑马程序员——多线程

------- android培训、java培训、期待与您交流! ----------

1.进程和线程的概念

       进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元。

  线程:是进程中的一个独立的控制单元,在控制着进程的执行。

  总之,一个进程中至少有一个线程。

2.自定义线程的方式

  (1)继承Thread类,覆盖run方法。

      步骤:<1>定义类继承Thread,目的是将自定义的代码存储在run方法中让线程运行。

           <2>覆写Thread类中的run方法,该方法有两个作用:启动线程和调用run方法。

      代码示例:

 

     

//创建线程的第一种方式//需求:创建两个线程,和主线程交替进行class Demo extends Thread{public Demo(String name){super(name);}//覆盖run方法public void run(){for(int i=0;i<50;i++){System.out.println(this.getName()+"在运行......."+i);}}}class ThreadDemo {public static void main(String[] args) {//创建线程对象Demo d1=new Demo("线程一");Demo d2=new Demo("线程二");d1.start();d2.start();for(int i=0;i<50;i++){System.out.println("主线程在运行........."+i);}}}

   (2)实现Runnable接口

       步骤:<1>定义类实现Runnable接口;

            <2>覆盖Runnable接口中的run方法;

            <3>通过Thread类建立线程对象;

            <4>将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;

            <5>调用Thread类的start()方法启动线程并调用Runnable接口子类的run方法。

      代码示例:

      

/*需求:简单的买票程序,多个窗口同时买票。*/class SaleTicket implements Runnable{private int ticket=100;//覆盖run方法public void run(){while(true){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){System.out.println(Thread.currentThread().getName()+"-----Exception------");}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}class SaleTicketDemo2{public static void main(String[] args) {//创建Runnable子类的实例对象SaleTicket st=new SaleTicket();//创造线程对象,将Runnable子类的实例对象作为参数进行传递Thread t1=new Thread(st);Thread t2=new Thread(st);Thread t3=new Thread(st);//启动线程t1.start();t2.start();t3.start();}}

以上两种方式,实现接口的方式避免了单继承的局限性,所以在定义线程时,建议使用实现接口的方式。

3.线程的运行状态:

  如下图所示:

 

4.多线程安全问题

  出现此问题的原因:当多条语句在操作同一个线程中的共享数据时,一个线程多条语句只执行了一部分,还没有执行完时,另一个线程参与进来执行。从而导致了共享数据的错误。

  解决方法有两种:同步代码块或者同步方法。

  (1)同步代码块:synchronized(对象){需要被同步的代码;}

      代码示例:

    

/*需求:简单的买票程序,多个窗口同时买票。*/class SaleTicket implements Runnable{private int ticket=100;Object obj=new Object();public void run(){while(true){//同步代码块synchronized(obj){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}}class SaleTicketDemo3{public static void main(String[] args) {SaleTicket st=new SaleTicket();Thread t1=new Thread(st);Thread t2=new Thread(st);Thread t3=new Thread(st);t1.start();t2.start();t3.start();}}


 

  (2)同步方法:只需要将方法进行同步就可以。

       代码示例:

       

/*同步代码块与同步函数互相切换。*/class SaleTicket implements Runnable{private int ticket=100;//定义标记用于切换boolean flag=true;public void run(){if(flag){while(true){//同步代码块synchronized(this){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}}elsewhile(true)method();}//同步方法public synchronized void method(){if(ticket>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");}}}class SaleTicketDemo4{public static void main(String[] args) {SaleTicket st=new SaleTicket();Thread t1=new Thread(st);Thread t2=new Thread(st);t1.start();try{Thread.currentThread().sleep(10);}catch(Exception e){System.out.println(Thread.currentThread().getName()+"-----Exception------");}st.flag=false;t2.start();}


 

 注意:同步的前提条件:

      <1>必须要有两个或者两个以上的线程;

      <2>必须是多个线程使用同一个锁;

      <3>必须保证同步中只能有一个线程在运行;

 同步的好处:解决了多线程的安全问题

 同步的弊端:多个线程需要判断对象锁,较为浪费资源。

 静态同步方法使用的对象锁是该方法所在类的字节码文件对象,即类名.class.

 代码实例:

 

      

    class SaleTicket implements Runnable{ private static int ticket=100; //定义标记用于切换 boolean flag=true; public void run() {  if(flag)  {   while(true)   {    //同步代码块    synchronized(SaleTicket.class)    {     if(ticket>0){      try{      Thread.sleep(10);      }      catch(Exception e)      {      }      System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");     }    }   }  }  else   while(true)   method(); } //静态同步方法 public static synchronized void method() {  if(ticket>0){     try{     Thread.sleep(10);     }     catch(Exception e)     {     }     System.out.println(Thread.currentThread().getName()+"卖了第有"+ticket--+"张票");    } }}class SaleTicketDemo5{ public static void main(String[] args)  {  SaleTicket st=new SaleTicket();  Thread t1=new Thread(st);  Thread t2=new Thread(st);  t1.start();  try{  Thread.currentThread().sleep(10);  }  catch(Exception e)  {  }  st.flag=false;  t2.start();  }}


 

5.线程间的通信

  线程间的通信其实就是多个线程在操作同一个资源,但是操作的动作不同。

  代码示例:

 

//线程之间的通信,通过等待唤醒机制来实现class Information{ private String name; private String sex; boolean flag=false; //同步方法 public synchronized void set(String name,String sex) {  //判断标记,如果为真表示已经赋值,应该等待被打印  if(this.flag)   {    try{     this.wait();     }    catch(Exception e){}   }  //赋值  this.name=name;  this.sex=sex;  //改变标记,表示赋值成功  this.flag=true;  //唤醒等待的线程  this.notify(); } public synchronized void get() {  //判断标记,如果为假,表示未被赋值,应该等待被赋值  if(!this.flag)   {    try    {     this.wait();    }    catch(Exception e)    {
System.out.println(Thread.currentThread().getName()+".......Exception....");    }   }  System.out.println(name+"----"+sex);  //改变标记,表示打印完毕  this.flag=false;  //唤醒等待的线程  this.notify(); }}//赋值线程类class Input implements Runnable{ private Information infor; public Input(Information infor) {  this.infor=infor; } public void run() {  boolean flag=true;  while(true)  {    if(flag)    {
//调用方法,完成赋值操作     infor.set("Apple","girl");     flag=false;    }    else    {     infor.set("小明","男孩");     flag=true;    }         } }} //输出线程类class Output implements Runnable{ private Information infor; public Output(Information infor) {  this.infor=infor; } public void run() {  while(true)  {
  //调用方法完成输出操作   infor.get();  } }}class ThreadComDemo { public static void main(String[] args)  {  Information infor=new Information();  new Thread(new Input(infor)).start();  new Thread(new Output(infor)).start(); }}

6.生产者与消费者模型

  使用同步方法的形式来实现:

  代码示例:

  

//多个生产者与消费者class ProCusDemo {public static void main(String[] args) {Resource r=new Resource();Producer pro=new Producer(r);Consumer con=new Consumer(r);Thread t1=new Thread(pro);Thread t2=new Thread(pro);Thread t3=new Thread(pro);Thread t11=new Thread(con);Thread t22=new Thread(con);Thread t33=new Thread(con);t1.start();t2.start();t3.start();t11.start();t22.start();t33.start();}}class Resource{private String name;private int count=1;private boolean flag=false;public synchronized void set(String name){//循环判断标记while(flag){try{wait();}catch (Exception e){
System.out.println("线程被终止!!!!!!");
}}this.name=name+"--"+count++;System.out.println(Thread.currentThread().getName()+"---生产者----"+this.name);flag=true;//唤醒所有this.notifyAll();}public synchronized void out(){//循环判断while(!flag){try{wait();}catch (Exception e){
System.out.println("线程被终止!!!!!!");
}}System.out.println(Thread.currentThread().getName()+"---消费者----"+this.name);flag=false;//唤醒所有this.notifyAll();}}//生产者class Producer implements Runnable{private Resource res;Producer(Resource res){this.res=res;}public void run(){while(true){res.set("+商品+");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res){this.res=res;}public void run(){while(true){res.out();}}}


JDK1.5中提供了多线程升级的解决方案:

 代码示例:

 

import java.util.concurrent.locks.*;//多个生产者与消费者class ProCusDemo2 {public static void main(String[] args) {Resource r=new Resource();Producer pro=new Producer(r);Consumer con=new Consumer(r);Thread t1=new Thread(pro);Thread t2=new Thread(pro);Thread t3=new Thread(pro);Thread t11=new Thread(con);Thread t22=new Thread(con);Thread t33=new Thread(con);t1.start();t2.start();t3.start();t11.start();t22.start();t33.start();}}class Resource{private String name;private int count=1;private boolean flag=false;private Lock lock=new ReentrantLock();private Condition pro_condition=lock.newCondition();private Condition con_condition=lock.newCondition();public  void set(String name){lock.lock();try{//循环判断标记while(flag)//生产者线程等待pro_condition.await();this.name=name+"--"+count++;System.out.println(Thread.currentThread().getName()+"---生产者----"+this.name);flag=true;//唤醒消费者线程con_condition.signalAll();}catch(InterruptedException e){System.out.println("线程被终止!!!!!!");}finally{//释放锁lock.unlock();}}public  void out(){lock.lock();try{//循环判断while(!flag)//消费者线程等待con_condition.await();System.out.println(Thread.currentThread().getName()+"---消费者----"+this.name);flag=false;//唤醒生产者线程pro_condition.signalAll();}catch (InterruptedException e){System.out.println("线程被终止!!!!!!");}finally{lock.unlock();}}}//生产者class Producer implements Runnable{private Resource res;Producer(Resource res){this.res=res;}public void run(){while(true){res.set("+商品+");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res){this.res=res;}public void run(){while(true){res.out();}}}

升级之后的解决方案,显示的对象所机制、显示的等待唤醒机制,一个锁可以对应多个Condition对象,可以实现在唤醒对方锁的同时不用唤醒己方锁,较之前的解决方案更好一些。

7.停止线程。

  解决思路:结束run方法。当开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。

  代码示例:

 

class Test implements Runnable{private boolean flag=true;public void run(){while(flag){System.out.println(Thread.currentThread().getName()+"...run");}}public void changeflag(){flag=false;}}class StopThreadDemo {public static void main(String[] args) {Test test=new Test();Thread t1=new Thread(test);Thread t2=new Thread(test);t1.start();t2.start();int number=0;while(true){if(number==50){test.changeflag();break;}number++;System.out.println(Thread.currentThread().getName()+"...run");}}}


特殊情况:当线程处于冻结状态,就不会读取到标记,此时可以通过调用interrupt()方法将处于冻结状态的线程强制恢复到运行状态。

 代码示例:

 

class Test implements Runnable{private boolean flag=true;public synchronized void run(){while(flag){try{wait();}catch (InterruptedException e){System.out.println(Thread.currentThread().getName()+"...Excption");flag=false;}System.out.println(Thread.currentThread().getName()+"...run");}}}class StopThreadDemo2 {public static void main(String[] args) {Test test=new Test();Thread t1=new Thread(test);Thread t2=new Thread(test);t1.start();t2.start();int number=0;while(true){if(number==50){//清除线程的冻结状态t1.interrupt();t2.interrupt();break;}number++;System.out.println(Thread.currentThread().getName()+"...run");}}}


8.线程池

  使用线程池来执行线程任务的步骤如下:

  (1)调用Executors类的静态方法创建一个ExecutorsService对象,该对象就代表一个线程池。

  (2)创建Runnable实现类的实例,作为线程执行任务。

  (3)调用ExecutorsService对象的submit()方法来提交Runnable示例。

  (4)当不想提交任何任务时,调用ExecutorsService对象的shutdown()方法来关闭线程池。

  代码示例:

 

import java.util.concurrent.*;class ThreadPoolDemo {public static void main(String[] args) throws Exception{//创建一个具有固定线程数的线程池ExecutorService pool=Executors.newFixedThreadPool(5);//向线程池中提交两个线程 pool.submit(new Demo()); pool.submit(new Demo());//关闭线程池pool.shutdown();}}//线程任务类class Demo implements Runnable{public void run(){for(int i=0;i<100;i++){System.out.println(Thread.currentThread().getName()+"----"+i+"-------");}}}


 

------- android培训、java培训、期待与您交流! ----------

 

 


 

 

 

  

 

 

0 0
原创粉丝点击