黑马程序员--java多线程

ASP.Net+Android+IO开发S.Net培训、期待与您交流!1、基础知识
进程:是指一个正在执行的程序,每一个进程执行,都有执行顺序,该顺序是一个执行路径,或者是一个控制单元
线程:就是进程中的一个独立的控制单元,线程控制着进程的执行,在线程执行中,至少有一线程执行
Vm 启动的时候有一个java.exe,该进程中至少有一个线程负责程序的执行,这个线程就是主线程
2.创建多线程
  1》、我们可以利用java中的Thread类创建线程,Thread是程序中执行的线程。创建线程时,1》、必须继承Thread类; 2》、同时应该覆盖Thread类的run方法;3》、创建线程对象,即创建
  所定义线程类的对象;4》开启线程,用对象的start方法(start的作用是:开启线程,并执行线程的run方法)
    public class ThreadDemo1 extends Thread{
 @Override
 public void run() {
  for(int i = 0; i< 60; i++)
  {
   System.out.println("thread run" +i);
  }
 }
  }执行时调用对象的start方法
  2》、线程的运行状态:五种状态,创建,运行,冻结,消亡,阻塞
  3》、线程有名称,可以通过getName()的到线程名称,通过setName()来设置线程名称
       自定义线程名称,我们通过调用父类的名称,亦可以通过;通过Thread.currentThread().getName()来获得当前线程的对象,currentThread是静态方法,获得那个线程是当前运行的对象
     小实例:买票程序的实现:多个窗口实现同时买票,这样就有共享资源,所以在程序中我们应该用Thread来实现时,我们应该考虑票是临界资源
  用Thread类实现时我们可以用静态变量来避免票被重复买
  public class Ticket extends Thread //implements Runnable
 {private static int ticket = 100;
  public Ticket(String name)
  {super(name);}
  public void run() {
   // TODO Auto-generated method stub
   while(true){
    if(ticket>0){
     System.out.println(Thread.currentThread().getName()+"  sale "+ticket--);
    }}}} 
 4》、创建线程类的第二种方法:
        步骤:1、定义实现Runnable接口的类
        2、覆盖Runnable接口中的run方法(run方法中为线程要执行的程序代码)
     3、通过Thread类来建立线程对象
     4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
      为啥要将Runnable接口的子类对象传递给Thread的构造函数
      原因:自定义的run方法所属的对象是Runnable接口的子类对象
      所以要让线程去指定对象的run方法。就必须明确该run方法所属对象
     5、调用Thread类的start方法开启线程并调用Runnable接口的run方法
       public class ThreadDemo2 implements Runnable {
   @Override
   public void run() {
    // TODO Auto-generated method stub
    for(int i = 0; i< 60; i++)
    {
     System.out.println(Thread.currentThread().getName()+"thread run" +i);
    }
   }
  }
  开启线程 Runnable r1 = new ThreadDemo2();  new Thread(r1).start();
 5》、实现方式和继承方式有什么区别? 
    实现方式避免了单继承的局限性,在定义线程时一般使用实现方式;继承Thread类线程代码存放在thread的子类的run方法中,而实现的线程代码在接口的子类run方法中
3、多线程的安全性问题,出现的原因
     当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完成
  另一个线程就获得了cpu的执行权,而执行其所要执行的语句,从而导致对共享数据的操作错误
   解决方法:对多条共享数据的语句用同步方式处理,只能让一个线程在某一时间段内执行,执行完成后,再将cpu的使用权让出,这样在一个线程执行的过程中,其他线程不参与执行
   1、java对于多线程的解决办法就是只用同步代码块的方式
    synchronized(对象)
 {
     //需要同步的代码语句块
 }
    同步的代码块应该是那些操作共享数据的代码块
 同步的原理:就是为资源的使用者上锁,当有线程使用共享资源是,对共享资源进行上锁,后来的线程等先来的线程将共享资源释放掉在使用共享资源,这样避免了CPU的使用权被后来
  的线程占用
 同步的前提是:1、必须要有两个或两个以上的线程共享同一资源;2、必须多个线程使用同一个锁,并且在同一段时间内只有一个线程在执行
 线程的同步解决了多线程中存在的安全问题,但是它较为消耗资源
   2、同步函数,带有synchronized修饰的函数为同步函数,同步函数也是用与解决多线程的安全性问题,同步函数使用的锁为this。只有两个锁相同时,对共享资源的访问才是安全的
     public synchronized void add(int n)
   {
    sum += n;
    try {
     Thread.sleep(10);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println("sum = "+sum);
   }
   3、使用静态同步函数时,所用的锁不是this啦,而是Class的对象这时锁就是所定义类的class对应的对象Class clazz = Ticket1.class;clazz为同步函数的锁
4、java多线程同步在单例模式中的应用
    单例模式的两种格式:饿汉式代码                                             懒汉式代码如下:(延时加载问题)
   class Single{                                                              class Single{
      private static final Single s = new Single();                              private static Single s = null;
   private Single(){}                                                         private Single(){}
   public static Single getInstance()                                         public static Single getInstance()
   {return s;}                                                                 { if(s == null) s = new Single();  return s;}
   }                                                                              }
   由上面代码可知道,当懒汉式用在多线程程序中时,可能会出现问题:有多个线程要实例化Single对象时,A线程判断s为空,线程进入睡眠状态;B线程在判断s还为空,这是B线程创建
   了一个Single对象,A再次运行时,不在判断s是否为空,就创建s对象,违背了单例设计模式,我们可以有两种解决问题方式
   class Single
   {
       private static Single s = null;
          private Single(){};
          public synchronized static Single getInstance()//这样每个进程进来都先判断锁是否开启,比较消耗资源
   {
      if(s == null) s = new Single();  return s;
   }
   }
  第二种解决方案:使用代码块的方式,减少锁的判断 (延迟加载的单例设计模式)
     class Single
   {
       private static Single s = null;
          private Single(){};
          public static Single getInstance()
   {
    if(s==null)
    {
       synchronized(Single.class){
         if(s == null) s = new Single();  return s;}
      }
   }
   }
5、多线程的死锁问题:出现的原因为同步中嵌套同步,而且两个锁不同引起的
6、线程间的通信
   1》、等待唤醒机制,其实现主要靠wait()和notify()方法
        其中wait方法让线程由运行状态变为冻结状态,冻结状态下,线程失去资源,没有执行的权利,只有当另外线程的唤醒(notify方法),才能从冻结状态转化为阻塞状态,
  有执行所需要的资源,wait,notify(),notifyAll()都使用在同步中,因为要对持有监视器(同步锁)的线程做操作,所以要使用在同步中,因为只有同步才具有锁
  synchronized(r)
   {
    if(!r.flag)
     try{r.wait();}catch(Exception e){}//将线程至于冻结状态
    System.out.println(r.name+"...."+r.sex);
    r.flag = false;
    r.notify();//拥有同样锁的线程可以唤醒拥有同样锁的等待进程,用notifyall可以唤醒拥有相同锁的其他等待进程
   }
  为什么这些操作的方法定义在Object类中?
  因为这些方法在操作同步中线程时,都必须要有标志他们所操作线程只有的锁,因为只有被同一个锁上的线程才可以被同一个锁上的notify唤醒
  即等待唤醒机制必须使用在同一个锁的同步代码块上,而锁可以是任意对象,因此wait和notify方法定义在Object中
   2》、生产者消费者问题
        在多个线程进行生产,多个进程进行消费的程序中我们应该用while进行判断,这样为了避免线程在为检测是否满足要求就去生产或者消费
          while(flag)
   try{this.wait();}catch(Exception e){}
   this.name = name+"\t"+count++;
   System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
   flag = true;
   this.notifyAll();//为了唤醒其他线程
     在jdk1.5以后java中提供了新的解决方案。利用java.util.concurrent.locks包下提供的Lock接口和Condition接口,这两个接口相互配合,实现多线程之间资源共享的问题
  Lock:替代了Synchronized
   lock
   unlock
   newCondition()
  Condition:替代了Object wait notify notifyAll
    await();
    signal();
    signalAll();
  实现的实例代码
  private Lock lock = new ReentrantLock();
   private Condition condition_produter = lock.newCondition();
   private Condition condition_consumer = lock.newCondition();
   public  void set(String name)throws InterruptedException
   {
    lock.lock();
    try
    {
     while(flag)
      condition_produter.await();
     this.name = name+"--"+count++;

     System.out.println(Thread.currentThread().getName()+"\t生产者\t"+this.name);
     flag = true;
     condition_consumer.signal();
    }
    finally
    {
     lock.unlock();//释放锁的动作一定要执行。
    }
   }
7、停止线程
   停止线程的原理:只有一种方法,即run方法的结束;开启多线程的运行,运行代码都是循环结构,所以我们只要控制住循环,就可以让run方法结束,也就是线程的结束
   在特殊情况:当线程
8、守护线程:我么可以通过Thread类中的setDaemon()方法可以将线程设置为守护线程,这时线程为后台线程,当前台线程结束后,后台线程自动结束,注意:该方法在开启线程时调用
9、join是线程抢夺CPU的执行权,其他线程将等待该线程执行完成后,在回到阻塞状态
    join的特点:当A线程执行到B线程的join方法时,A就会等待,等待B线程执行完,A才会执行,join可以用来临时加入线程执行
10、Priority和Yield
     优先级,在java多线程中线程有优先级,优先级越高,其抢占到资源的概率越高
     yield() 
 ASP.Net+Android+IO开发S.Net培训、期待与您交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值