您的位置:首页 > 职场人生

黑马程序员 Java基础 --->多线程

2013-04-11 14:30 471 查看

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

多线程

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

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

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

1,如何在自定义的代码中,自定义一个线程呢?

   通过对api的查找,java已经提供了对线程这类事物的描述。就Thread类。

发现运行结果每一次都不同

   因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。

创建线程的第一种方式:继承Thread类。

   步骤:

   1,定义类继承Thread。

   2,复写Thread类中的run方法。目的:将自定义代码存储在run方法。让线程运行。

   3,调用线程的start方法,该方法两个作用:启动线程,调用run方法。

创建线程的第二种方式:实现Runable接口

步骤:

   1. 定义类实现Runnable接口

   2. 覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。

   3. 通过Thread类建立线程对象。将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

   4. 为什么要将Runnable接口的子类对象传递给Thread的构造函数。因为,自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。

   5. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

实现方式和继承方式有什么区别呢?

   实现方式好处:避免了单继承的局限性。

   在定义线程时,建立使用实现方式。

两种方式区别:

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

   实现Runnable,线程代码存在接口的子类的run方法。

多线线程常用方法:

   sleep()     让当前线程睡眠(需要接受一个整数以毫秒计算)

   notify()     唤醒第一个被等待的线程

   wait()     让当前线程处于等待状态

   notifyAll()    唤醒所有的线程

   await() 让当前线程处于等待状态

   signal()     唤醒第一个被等待的线程

   signalAll()    唤醒所有线程

   unlock()    释放锁

   interrupt()   中断状态:中断冻结状态重新回到运行状态

   setDaemon()   将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调

   join()      当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。

多线程的运行出现了安全问题。

问题的原因:

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

解决办法:

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

  Java对于多线程的安全问题提供了专业的解决方式。就是同步代码块。

  synchronized(对象)

  {

  需要被同步的代码

  }

  对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

同步的前提:

  1,必须要有两个或者两个以上的线程。

  2,必须是多个线程使用同一个锁。必须保证同步中只能有一个线程在运行。

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

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

线程同步的两个实例:

实例一:[b]用synchronized来实现同步[/b]

class Demo
{
  public static void main(String[]args)
  {
    Resource res = new Resource();	//创建一个Resource类对象
    Consumer com = new Consumer(res);	//创建一个Consumer类对象,将res存进去
    Producer pro = new Producer(res);	//创建一个Producer类对象,将res存进去
    Thread t1 = new Thread(com);		//创建一个线程类对象,将com存进去
    Thread t2 = new Thread(com);		//创建一个线程类对象,将com存进去
    Thread t3 = new Thread(pro);		//创建一个线程类对象,将pro存进去
    Thread t4 = new Thread(pro);		//创建一个线程类对象,将pro存进去
    t1.start();		//开启线程
    t2.start();		//开启线程
    t3.start();		//开启线程
    t4.start();		//开启线程
  }
}
class Resource
{
    private String name; 		//产品名称
    private int count =1;		//产品编号
    private boolean flag = false;		//标记

    public synchronized void set(String name)   //加上synchronized修饰方法 让该方法同步
    {
      while (flag)       //判断标记
      {
        try
        {
          wait(); 	//让当前线程回到等待状态
        }
        catch (Exception e)
        {
        }
      }
      this.name = name +"  "+count++;	//把获取到的name和count赋值给成员变量name
      System.out.println(Thread.currentThread().getName()+"....生产...."+this.name);   //打印线程名称和成员变量
      flag = true;	//更改标记
      notifyAll();	//唤醒所有等待线程
    }
    public synchronized void out() //加上synchronized修饰方法 让该方法同步
    {
      while (!flag)	//判断标记
      {
        try
        {
         wait();	//让当前线程回到等待状态
        }
        catch (Exception e)
        {
        }
      }
      System.out.println(Thread.currentThread().getName()+"...消费..."+name);//打印线程名称和成员变量
      flag = false;	//更改标记
      notifyAll();	//唤醒所有等待线程
    }
}
class Producer implements Runnable 	//继承线程接口
{
    private Resource res;	//定义一个Resource类的引用类型函数
    Producer(Resource res)	//接收一个存进来的Resource类型对象
    {
      this.res =res;	//把成员变量res指向接受进来的对象
    }
    public void run()
     {
      while (true)
      {
        res.set(" 商品 ");	//调用Resource类的set方法
      }
    }
}
class Consumer implements Runnable
{
    private Resource res;	//定义一个Resource类的引用类型函数
    Consumer(Resource res)	//接收一个存进来的Resource类型对象
    {
      this.res =res;		//把成员变量res指向接受进来的对象
    }
    public void run()
    {
      while (true)
      {
        res.out();		//调用Resource类的out方法
      }
    }
}


实例二:用Lock来实现同步

class Demo
{
    public static void main(String[]args)
    {
       Resource res = new Resource();    //创建一个Resource类对象
       Consumer com = new Consumer(res);   //创建一个Consumer类对象,将res存进去
       Producer pro = new Producer(res);   //创建一个Producer类对象,将res存进去
       Thread t1 = new Thread(com);        //创建一个线程类对象,将com存进去
       Thread t2 = new Thread(com);        //创建一个线程类对象,将com存进去
       Thread t3 = new Thread(pro);        //创建一个线程类对象,将pro存进去
       Thread t4 = new Thread(pro);        //创建一个线程类对象,将pro存进去
       t1.start();     //开启线程
       t2.start();     //开启线程
       t3.start();     //开启线程
       t4.start();     //开启线程    
    }

}
import java.util.concurrent.locks.*;     //导入包
class Resource
{
    private String name;   //产品名称
    private int count =1;  //产品编号
    private boolean flag = false;   //标记
    private Lock lock = new ReentrantLock();   //创建一个锁
    private Condition condition_sc = lock.newCondition();     //创建一个Condition对象
    private Condition condition_xf = lock.newCondition();     //创建一个Condition对象

    public void set(String name)
    {
       lock.lock();    //获取锁
       try
       {
          while (flag)  //判断标记
          {
             try
             {
               condition_sc.await();    //让当前线程回到等待状态
             }
             catch (Exception e)
             {
             }
          }
          this.name = name +"  "+count++;        //把获取到的name和count赋值给成员变量name
          System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name);   //打印线程名称和成员变量
          flag = true;        //更改标记
          condition_xf.signal();     //唤醒线程
       }
       finally
       {
          lock.unlock();      //释放锁
       }
    }

    public  void out()
    {
      lock.lock();      //获取锁
      try
      {
         while (!flag)     //判断标记
         {
            try
            {
               condition_xf.await();    //让当前线程回到等待状态
            }
            catch (Exception e)
            {
            }
            System.out.println(Thread.currentThread().getName()+"...消费者..."+name);   //打印线程名称和成员变量
            flag = false;        //更改标记
            condition_sc.signal();       //唤醒线程
         }
         finally
         {
            lock.unlock();    //释放锁
         }
    }
}
class Producer implements Runnable
{
    private Resource res;      //定义一个Resource类的引用类型函数
    Producer(Resource res)      //接收一个存进来的Resource类型对象
    {
       this.res =res;         //把成员变量res指向接受进来的对象
    }
    public void run()
    {
       while (true)
       {
          res.set(" 商品 ");    //调用Resource类的set方法
       }
    }
}
class Consumer implements Runnable
{
    private Resource res;    //定义一个Resource类的引用类型函数
    Consumer(Resource res)   //接收一个存进来的Resource类型对象
    {
       this.res =res;      //把成员变量res指向接受进来的对象
    }
    public void run()
    {
       while (true)
       {
          res.out();     //调用Resource类的out方法
       }
    }


----------- android培训java培训、java学习型技术博客、期待与您交流! ------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: