黑马程序员——多线程

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

Day11——多线程   java.lang

*01-线程(概述)

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

   2、线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程

   3JavaVM  启动时会有一个进程java.exe。该进程至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中,该线程称之为主线程

    扩展:其实更细节说明jvmjvm启动不止一个线程,还有负责垃圾回收的线程

   

 

*02-创建线程-继承Thread

通过对API的查找,java提供了对线程这类事物的描述,就是Thread类。在java.lang包中

 

   、创建线程的第一种方式,继承Thread

       步骤:a\定义类继承Thread

             b\复写Thread类中的run方法;

                 目的:定义线程需要执行的代码,run方法就是存储线程要执行的代码

             c\调用线程的strat方法(该方法两个作用:启动线程,调用run方法)

 

03-多线程(创建线程-runstart特点)

为什么要复写run方法?

   定义线程需要执行的代码,run方法就是存储线程要执行的代码

 

为什么不直接用d.run();?而要用d.start();?

    d.run()仅仅是对想调用方法,而线程创建了,并没有运行。

 

05-多线程(线程运行状态)

注意:还有一个状态(临时状态) 阻塞 具备执行资格,但没有执行权,可能cpu在执行别的线程。当冻结的线程被唤醒了他最初会到阻塞状态,再判断cpu是否空闲,空闲时到运行状态

                                                 阻塞 

                                                                  sleep()  ,wait()

被创建  start()   ------------>   运行  < ------------------------->冻结(放弃执行资格)

                                                    |            Sleep()  notify()

                                           Run()结束

                                             或  Stop()方法

                             Stop()        消亡

 

06-多线程(获取线程对象以及名称)

发现运行结果每一次都不同,因为多个线程都在获取cpu的执行权,在某个时刻,只能有一个程序在运行(除多核外),cpu在做快速的切换,以达到看上去是同时执行的效果。我们可以形象的把多线程的运行行为看作是相互抢夺cpu的执行权、

 

   1 、线程都有自己的名称  Thread-编号  编号从开始

   2 、也可以自定义线程名称,

       在线程构造方法中ZiThread(String name){super(name)}

   3 、设置线程名称:setName()或者构造函数

       获取线程名称:getName()

   4 staticThread currentThread();获取当前线程对象

 

 

08-创建线程-实现Runnable接口

  1Runnable接口应该由那些打算通过某一线程执行其实例的类来实现,

      类必须定义一个run的无参数方法

  、创建线程的第二种方式,实现Runnable接口

      步骤:a\定义类实现Runnable接口;

            b\覆盖Runnable接口中的run方法;

                将线程要运行的代码存放在改run方法中

            c\通过Thread类建立线程对象;

            d\Runnable接口的子类对象传递给Thread的构造函数

  3 、为什么要将Runnable接口的子类对象传递给Thread的构造函数?

       因为自定义的run方法所属的对象是Runnable接口的子类对象;所以要让线程去指定 指定对象的run方法,就必须明确该run方法所属的对象

 

  **********注意:实现接口和继承方式有什么区别??????

     实现方式的好处:避免了单继承的局限性;在定义线程时,建议使用实现方式

 

     两种方式的区别:

          继承Thread:线程代码存放在Thread子类run方法中

          实现Runnable:线程代码存放在接口的子类run方法中

09-多线程(多线程的安全问题)  (售票问题同步后代吗)

   class Ticketimplements Runnable

   {

       private int tick = 100;     //堆内存中

 

       Object obj = new Object();

       // public synchronized) void run()(也可以把synchronized放函数上做为修饰符)

       public  void run()

      {

       while(true)

       {

               synchronized (obj)

               {

                      if(tick>0)

                      {

                             try{Thread.sleep(10);}catch(Exception e){}

                       System.out.println(Thread.currentThread().getName()+"^^sale:"+tick--);

                      }

                  }

          }

       }

    }

 

    class TicketDemo

    {

       public static void main(String[]args)

      { 

          Ticket t = new Ticket ();

          Thread t1 = new Thread(t);

          Thread t2 = new Thread(t);

          Thread t3 = new Thread(t);

          Thread t4 = new Thread(t);

          t1.start();

          t2.start();

          t3.start();

          t4.start();

       }

     }

   1\买票问题——有四个线程对全局变量Tick操作,当Tick>0时售票(线程操作Tick)发现打印出了0-1-2等错票

 

   2\多线程运行出现安全问题原因:

       当多个线程在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,(然后让他睡眠),还没执行完,另一个线程参与进来执行。导致共享数据的错误

   3、解决办法

       对多个操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行

 

10-多线程(多线程同步代码块)

        java对多线程的安全问题提供了专业的解决方式(同步代码块)

        synchronized(对象){需要被同步的代码(也就是有共享数据的代码)}

 

     4对象如同锁,持有锁的线程可以在同步代码块中执行,没有持有锁的线程即使获取cpu执行权也进不去,因为没有获取锁(信号量:0,1)当信号量为1时代表可以通过

 

        火车上的卫生间——经典

        

     5、同步的前提:必须要有两个或以上线程;必须是多个线程使用同一锁*(同一个对象)

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

        弊端:多个线程需要判锁,较为耗费资源

 

11-多线程(多线程-同步函数)

public synchronized) voidrun(){}

如何找问题:

1:明确那些代码是多线程运行代码

2:明确共享数据

3:明确多线程运行代码中那些语句是操作共享数据的

 

同步函数用的是哪一个锁呢?

    函数需要被对象调用,那么函数都有一个所属对象引用,就是this。所以同步函数使用的锁就是this

 

如果同步函数被static修饰后,使用的锁是什么?

发现不是this,因为静态方法中也不可以定义this

静态进内存时,内存中没有本类对象。但是一定有该类对应的字节码文件对象。类名.class。该对象类型是class

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

 

 

 

14-多线程(多线程-单例设计模式-懒汉式)

   单例设计模式:

 1:饿汉式

Class Single

{

     private static final Single s = new Single();

     private Single(){}

     public static Single getInstance()

     {

         return s 
         } 
    }

 

2:懒汉式(请写出一个延迟加载的单例设计模式示例)

Class Single

{

     private static Single s = null;

     private Single(){}

     public static Single getInstance()

     {

         if(s==null)    //避免每次都判断锁,只有当对象为null时才判断

         {

              synchronized(Single.class)

              {

                   if(s==null)  //如果一个线程跑到第一个if后死了,另一个线程进来创建了对象释放了锁,然后那个线程醒了,进来后还要判断

                   {

                       s = new Single();

                    }

              }

          }

           return s

      } 
    }

问:1、懒汉式和饿汉式有什么不同?

         懒汉式的特点在于延迟加载(实例的延迟加载)

2‘懒汉式延迟加载有没有问题?怎么解决?

     有,如果多线程访问时存在安全问题;可以加同步解决synchronized

    3加同步的方式?

          用同步函数和同步代码块都行。稍微有些低效(每次要判断锁),利用双重判断的形式能解决效                       率问题。

4、加同步的时候使用的锁是哪一个?

      是该类所属的字节码文件对象

    

 

15-多线程(多线程-死锁)

 死锁:同步中嵌套同步

public void run()

       {

              if(flag)

              {

                     while(true)

                     {

                            synchronized (ob1)

                            {

                                   System.out.println("ifob1");

                                   synchronized (ob2)

                                   {

                                          try {wait();}catch(InterruptedException e) {}

                                          System.out.println("ifob2");

                                   }

                            }

                     }

              }

              else

              {

                     while(true)

                     {

                            synchronized (ob2)

                            {

                                   System.out.println("ifob2");

                                   synchronized (ob1)

                                   {

                                          try {wait();}catch(InterruptedException e) {}

                                          System.out.println("ifob1");

                                   }

                            }

                     }

              }

       }

 

Day12——多线程

 

01-多线程(线程间通信-示例代码)

思考:一:wait(), notify() ,notify All(),用来操作线程为什么定义在了Object类中?

       1:这些方法存在于同步中;

       2:使用这些方法时必须要标示所属的同步锁;

       3:锁可以是任意对象,所以任意对象调用的方法一定定义在Object

     二: wait()   sleep() 有什么区别?

       wait()   :释放资源,释放锁  

       sleep()   :释放资源,不释放锁

 

 

1、线程间通讯:

其实就是多个线程在操作同一个资源;但是操作的动作不同(比如一个放,一个拿)

 

03-多线程(线程间通信-等待唤醒机制)  等一个线程做完后才唤醒另一个线程

   1wait()    notify()  notifyAll()

都使用在同步中,因为要对持有监视器(锁)的线程操作;所以要使用在同步中,只有同步才具有锁

   2、为什么这些操作现成的方法要定义在Object类中呢?

      因为 这些方法在操作同步中线程时,都必须要标示他们所操作线程持有的锁。只有同一个锁上的被等待的线程,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中

/*

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

 * 等待唤醒机制:当一个线程在执行时,要等他完全执行完再去唤醒另一个线程

 */

 

class Res

{

       private Stringname;

       private Stringsex;

       private   boolean flag = false;

       public synchronized  void set(Stringname,String sex)

       {

              if(flag)

                     try{this.wait();}catch(Exception e){}

              this.name = name;

              this.sex = sex;

              flag = true;

              this.notify();    //锁调用

       }

       public synchronized void out()

       {

              if(!flag)

                     try{this.wait();}catch(Exception e){}

              System.out.println(name+"^^"+sex);

              flag = false;

              this.notify();

       }

}

 

class Input implements Runnable

{

       private Resr;

       Input(Resr)

       {

              this.r = r;

       }

       public void run()

       {

              int x=0;

              while(true)

              {

                     if(x==0)

                     {

                            r.set("mike","nan");

                    }

                     else

                     {

                            r.set("丽丽","");

                     }

                     x=(x+1)%2;

                     }

              }

}

 

class Output implements Runnable

{

       private Resr;

       Output(Resr)

       {

              this.r = r;

       }

       public void run()

       {

              while(true)

              {

                     r.out();

              }

       }

}

 

public class InputOutputDemo 

{

       public static void main(String[] args)

       {

              Resr = new Res();

              new Thread(new   Input(r)).start();

              new Thread(new   Output(r)).start();

       }

}

 

 

05-多线程(线程间通信-生产者消费者)

   对于多个生产者和消费者,定义while判断标记:让被唤醒的线程再一次判断标记

   定义notifyAll,因为要唤醒对方线程。如果只用notify,容易出现只唤醒本方线程,导致程序中的所有线程都等待

   //多个生产者生产,多个消费者消费

public classProducerConsumerDemo 

{

       public static void main(String[]args)

       {

              Resourcer = new Resource();

              Producerpro = new Producer(r);

              Consumercon = new Consumer(r);

              

              Threadt1= new Thread(pro);

              Threadt2= new Thread(pro);

           Thread t3 = new Thread(con);

           Thread t4= new Thread(con);

           t1.start();

           t2.start();

           t3.start();

           t4.start();

       }

}

//商品类

class Resource

{

       private Stringname;

       private int count = 1;

    private boolean flag = false;

    public synchronized void set(String name)

    {

    while(flag)     //为什么用while不用if,因为让醒的线程再去判断标记,这样会避免数据错乱

            try{this.wait();}catch(Exception e){}

    this.name = name+"--"+count++;

    System.out.println(Thread.currentThread().getName()+"^生产者^"+this.name);

    flag = true;

    //为什么不用this.notify()因为他只会唤醒线程池中第一个线程,

    //,但是线程醒后又去判断标记,容易出现线程全部等待,但不是死锁

    this.notifyAll(); 

    }

      public synchronized void out()

    {

    while(!flag)

                  try{wait();}catch(Exception e){}

    System.out.println(Thread.currentThread().getName()+"^消费者^^^^"+this.name);

    flag = false;

           this.notifyAll(); 

    }

}

//生产者

class Producerimplements Runnable

{

       private Resourceres;

       Producer(Resourceres)

       {

              this.res = res;

       }

       public void run()

       {

              while(true)

              {

                     res.set("+商品+");

              }

       }

}

//消费者

class Consumerimplements Runnable

{

       private Resourceres;

       Consumer(Resourceres)

       {

              this.res = res;

       }

       public void run()

       {

              while(true)

              {

                     res.out();

              }

       }

}

06-多线程(线程间通信-生产者消费者JDK5.0升级版)

Java util.concurrent locks

   JDK1.5中提供了线程升级解决方案。

将同步synchronized替换成现实Lock操作;

Object中的wait,notifynotifyAll替换成了Condition对象,该对象可以Lock锁,进行获取;

该实例中实现了本方只能唤醒对方的操作。

 

importjava.util.concurrent.locks.*;

//多个生产者生产,多个消费者消费

public class ProducerConsumer_2

{

       public static void main(String[]args)

       {

              Resource_2r = new Resource_2();

              Producer_2pro = new Producer_2(r);

              Consumer_2con = new Consumer_2(r);

              

              Threadt1= new Thread(pro);

              Threadt2= new Thread(pro);

           Thread t3 = new Thread(con);

           Thread t4= new Thread(con);

           t1.start();

           t2.start();

           t3.start();

           t4.start();

       }

}

//商品类

class Resource_2

{

       private Stringname;

       private int count = 1;

    private boolean flag = false;

    

    private Locklock = new ReentrantLock();

    

    private Conditioncondition_pro = lock.newCondition();

    private Conditioncondition_con = lock.newCondition();

    

    public  void set(String name) throwsInterruptedException

    {

    lock.lock();//拿到锁

    try

    {

           while(flag)     //为什么用while不用if,因为让醒的线程再去判断标记,这样会避免数据错乱

                   condition_pro.await(); //让生产者等待

           this.name = name+"--"+count++;

           System.out.println(Thread.currentThread().getName()+"^生产者^"+this.name);

           flag = true;

           condition_con.signal();//唤醒消费者,不用唤醒全部线程,这样也可以避免全部等待

    }

    finally

    {

            lock.unlock();

    }

    }

      public  void out() throwsInterruptedException

    {

             lock.lock();

             try

             {

                    while(!flag)

                           condition_con.await();

                    System.out.println(Thread.currentThread().getName()+"^消费^^^^"+this.name);

                    flag = false;

                    condition_pro.signal();

             }

             finally

             {

                    lock.unlock();

             }

    }

}

//生产者

class Producer_2implements Runnable

{

       private Resource_2res;

       Producer_2(Resource_2res)

       {

              this.res = res;

       }

       public void run()

       {

              while(true)

              {

                     try

                     {

                            res.set("+商品+");

                     }

                     catch(InterruptedExceptione)

                     {

                            

                     }

                     

              }

       }

}

//消费者

class Consumer_2implements Runnable

{

       private Resource_2res;

       Consumer_2(Resource_2res)

       {

              this.res = res;

       }

       public void run()

       {

              while(true)

              {

                     try

                     {

                            res.out();

                     }

                     catch(InterruptedExceptione)

                     {

                            

                     }                    

              }

       }

}

 

 

 

 

07-多线程(停止线程)

   stop() 方法已经过时,如何停止线程?

    只有一种,run()方法结束。开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run()方法结束,也就是线程结束

 

特殊情况:当线程处于冻结状态(不是运行状态),就不会读取到标记,线程就不会结束

           当没有指定的方式让冻结的线程恢复到运行状态时,需要对冻结进行清除,强制让线程恢复到运行状态,这样就可以操作标记让线程结束,Thread类提供该方法interrupt()

 

注::::t1.interrupt(); 强制让冻结状态的线程恢复到运行状态,t1冻结的地方会抛出IterruptedException异常,处理该异常时(catch{改变标记},来停止线程

 

class StopThreadimplements Runnable

{

       private boolean flag = true//判断标记,让线程结束

       public synchronized void run()

       {

              while(flag)

              {

                     try

                     {

                            wait();

                     }

                     catch(InterruptedExceptione)

                     {

                            System.out.println(Thread.currentThread().getName()+"……Exception");

                            flag =false;  //当发生异常,说明调用了interrupt方法强制线程清楚冻结,希望线程停

                     }

                     System.out.println(Thread.currentThread().getName()+"……run");

              }

       }

       public void changFlag()

       {

              flag = false;

       }

}

 

public class StopDemo 

{

       public static void main(String[]args)

       {

              StopThreadst = new StopThread();

              

              Threadt1 = new Thread(st);

              Threadt2 = new Thread(st);

              t1.start();

              t2.start();

              

              int num = 0;

              while(true)

              {

                     if(num++ == 60)

                     {

                            t1.interrupt();//让冻结的线程恢复到运行妆状态

                            t2.interrupt();

                            break;

                     }

                     System.out.println(Thread.currentThread().getName()+"……"+num);

              }

              System.out.println("over");

       }

}

 

08-多线程(守护线程)(后台线程)

  T1.setDaemon(true);将该线程标记为守护线程或用户线程。 

   当正在运行的线程都是守护线程时,Java虚拟机退出,程序结束。

 

注意:一个线程被标示为守护线程,并不是他不运行了,他跟其他线程一样运行。只是当前台线程执行完后,这些线程否会结束

 

09-多线程(Join方法)

   Join():A线程执行到了B线程的.join()方法时,A线程就会让出cpu执行权,等待直到B线程执行完,A才会执行。Join可以用来临时加入线程执行。

注意:碰见了谁的join()方法,就只等谁。等他结束就执行。

t1.start();

t1.join();  //等待t1执行完,才继续执行主线程和其他线程,其他线程在期间是冻结的

t2.start();

 

t1.start();

t2.start();

t1.join(); //当主线程执行到这里,他会冻结,但是t2不会冻结,他和t1交替执行,主线程等t1执行完了才执行,不管t2有没有执行完

 

10-多线程(优先级&yield方法)

    优先级:t1.setPriority(int newPriority);设置线程优先权,1-10,默认5,越大,抢到cpu执行权机会越大;(Thread.MAX_PRIORITY,  MIN_PRIORITY ,NORM_PRIORITY

    yield():暂停当前正在执行的线程,并执行其他线程,Thread.yield();

 

总结:当程序中需要几个动作需要同时进行时,可以用到线程

 

      用匿名类:1: newThread()

                {

                    Public void run(){}

                }.start();

      

                2: Runnable  r = new  Runnable()

                 {

                     Public void run(){}

                 } ;

                  new  Thread(r).start();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值