黑马程序员——多线程

来源:互联网 发布:打鼓谱软件 编辑:程序博客网 时间:2024/06/05 05:27


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

要了解线程,就要了解进程,线程和程序之间相互关系。

1.      进程是程序的一次执行过程,从源代码加载,执行,直至完成一个完整过程。

2.      线程是控制流,也是一个执行过程,但执行单位比进程小。

线程与进程比较:

共同点:

都是一个程序的执行过程。

不同点:

进程是一个实体,每个进程有自己的状态,专用数据段(独立内存资源);同一个进程下的线程则共享进程的数据段。

3.      线程的生命周期

一个线程的创建,工作,死亡的过程称为线程的生命周期。

线程生命周期公有5个阶段:新建状态,就绪状态,运行状态,阻塞状态和死亡状态。

①.             新建状态:新建状态是指创建一个线程,但它还没启动。处于新建状态的线程对象,只能够被启动或终止。Example:以下代码使线程myThread处于新建状态:

Thread myThread= new Thread();

②.             就绪状态:就绪状态是当线程处于新建状态后,调用了start()方法,线程就处于就绪状态。

就绪状态具备运行条件,但尚未进入运行状态。处于就绪状态的线程可有多个,这些线程将在就绪队列中排队,等待cpu资源。

Example:以下代码使线程myThread进入就绪状态:

myThread.start();

③.运行状态:

运行状态就是某个就绪状态的线程获得了cpu资源,正在运行。

④     .阻塞状态:

阻塞状态就是正在运行的线程遇到某个特殊情况:例如:延迟,挂起,等待I/O操作完成等。

⑤.死亡状态

       线程不具有继续运行的能力,也不能转到其他的状态。

4.      线程调度与优先级

线程调度采用抢占式,优先级高的比优先级低的优先运行。

优先级相同的情况下,按先来先服务的原则运行。

5.      java实现多线程应用有两种途径。

①.继承Thread类,申明Thread子类,用Thread子类创建线程对象。

②.在类中实现Runnable接口,在类中提供Runnable接口的run()方法。

6.      Thread类

①.定义继承Thread方法。

②.复写Thread类中的run方法。目的是将自定义的方法存储在run方法中,让线程运行。

③.调用start方法,该方法有两个作用:启动线程,jvm调用run方法。

 

例如程序:

class Demo extends Thread

 

{

    private Stringname;

    Demo(String name)

    {

       this.name=name;

    }

    public void run()

    {

       for(int i=0;i<10;i++)

       {

       System.out.println(this.getName()+"\tgood luckto myself"+i);

       }

    }

   

}

 

 

public class univer

{

       public static void main(String[] args)

       {

           Demo t1 = new Demo("one+");

           Demo t2 = new Demo("two+");       

          

           t1.start();

           t2.start();

           for(int j=0;j<10;j++)

           {

              System.out.println("main......"+j);

           }

       }

}

程序分析:

Demo类继承Thread类,复写run方法。

New Demo()建立线程。t1.start();t2.start();开启线程,使线程处于就绪状态。由jvm觉得运行谁。

getName()是获取线程的名字。从这个方法可以看出,线程有默认的名字。

例如:Thread-1 good luckto myself7

Thread-1 good luckto myself8

Thread-1 good luckto myself9

Thread-0 good luckto myself9

线程默认名为:类名—编号。编号从0开始。

另外:注意Thread类的另一个方法:static Thread currentThread()方法,返回当前正在执行线程一个引用:故this ==Thread.currentThread()即有:Thread.currentThread().getName();相当于this.getname();

7.      实现接口Runnable:

Java.lang.Runnable接口,只有run方法需要实现,一个实现Runnable接口的类实际上定义了一个在主线程之外的新线程的操作。

①.  定义类实现Runnable接口

②.  覆盖Runnable接口中的Run方法。将要运行的代码放在该run方法中。

③.  通过Thread类建立线程对象。

④.  将Runnable子类对象作为实际参数传递给Thread类的构造函数。

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

因为:自定义run方法所属的对象是Runnable子类对象。

所以要让线程去指定对象的run方法。就必须明确该run方法所属的对象。

⑤.  调用Thread类的start方法开启线程。并由jvm调用Runnable子类的run方法。

⑥.  实现方式和继承方式的区别?

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

Example:

class Demo implements Runnable

 

{

    private Stringname;

    Demo(String name)

    {

       this.name=name;

    }

    public void run()

    {

       for(int i=0;i<10;i++)

       {

       System.out.println(name+"\tgood luckto myself"+i);

       }

    }

   

}

 

 

public class univer

{

       public static void main(String[] args)

       {

           Demo d1 = new Demo("one");

           Demo d2 = new Demo("two");

           Thread t = new Thread(d1);

           Thread t1 = new Thread(d2);

           t.start();

           t1.start();

           for(int j=0;j<10;j++)

           {

              System.out.println("main......"+j);

           }

       }

}

程序实现了Runnable接口,创建了两个线程,加上主线程,给程序一共三个线程。

7.线程的同步于互斥

通常情况下,程序中多个线程是相互协调和相互联系的,多线程之间存在着互斥与同步。

发生同步的原因:

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

class Ticket implements Runnable

 

{

    private int tick=10;

    public void run()

    {

       while(true)

       {

           if(tick>0)

           {

       for(int i=0;i<10;i++)

       {

       System.out.println("\tgood luckto myself"+tick--);

       }

           }

    }

    }

   

}

 

 

public class univer

{

       public static void main(String[] args)

       {

           Ticket i = new Ticket();

           Thread t = new Thread(i);

           Thread t1 = new Thread(i);

           t.start();

           t1.start();

           for(int j=0;j<10;j++)

           {

              System.out.println("main......"+j);

           }

       }

}

程序分析:改程序有两个线程:t和t1,开启线程后,t和t1共享数据tick,t进入到if(tick>0)后,t1由于tick还是大于0,满足条件。故t,t1都进入if语句内部。

当tick=1时,t和t1给tick减了两次,故造成了tick数据的错误:

解决办法:

对多条操作共享数据,每次只允许一个线程对其进行操作,其他线程不能进入:

专业解决方式:同步代码块:

Synchronized(对象)

{

    需要被同步代码;

}

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

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

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

Example:

class Ticket implements Runnable

 

{

    private int tick=10;

    Object obj = new Object();

    public void run()

    {

       while(true)

       {

           synchronized(obj)

           {

           if(tick>0)

           {

       for(int i=0;i<10;i++)

       {

       System.out.println("\tgood luckto myself"+tick--);

       }

           }

           }

    }

    }

   

}

 

 

public class univer

{

       public static void main(String[] args)

       {

           Ticket i = new Ticket();

           Thread t = new Thread(i);

           Thread t1 = new Thread(i);

           t.start();

           t1.start();

           for(int j=0;j<10;j++)

           {

              System.out.println("main......"+j);

           }

       }

}

注意:synchronized(对象)括号里面的对象只是一个对象,这个对象可以是任何类自定义类的对象,对象与程序没有太大关系。对象只是提供了一个锁的机制。

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

 详情请查看:http://edu.csdn.net/heima

原创粉丝点击