黑马程序员_日记12_多线程(二)

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

线程的运行状态

线程的运行状态在这里我们划分为五种状态。
依次为:被创建,运行,冻结,消亡,阻塞。
它们的关系见下图:
线程运行状态及其关系

如上图所示:
- 线程在经初始化被创建后通过start方法被调用,进入了运行状态。
- 线程会因run方法运行结束或者强制终止而消亡。
- 线程会因为sleep进入冻结状态,当时间达到,又转入运行状态。
- 线程还会因为wait而进入冻结状态,因为notify方法而进入运行状态。
- 线程还会因为某些原因进入阻塞状态,再从阻塞状态转入运行状态。

需要注意的地方是:
- 运行是指具备运行资格,并具有执行权;
- 阻塞是指具备运行资格,但没有执行权;
- 冻结是指没有运行资格,但有执行权。

创建线程的第二种方式(Runnable)

下面通过售票的例子来推演创建线程的第二种方式。

需求:简单的卖票程序。多个窗口同时买票。

创建线程的第一种方式

步骤:
1、创建售票线程类,继承Thread
2、覆盖run方法(把需要让线程执行的代码写在run的方法体)
3、创建线程对象,调用start方法

代码1
//建立售票线程类
class TicketThread extends Thread
{
    //私有化票额
    private int ticket =30 ;

    //覆盖run方法
    public void run()
    {
            //建立一个循环售票,当票售完即停止
            while(ticket > 0)
            {
                //打印当前线程对象售出的票号
                System.out.println("Ticket "+ticket+" is saled by "+Thread.currentThread().getName());
                //票号减一
                ticket--;
            }
    }
}

class ThreadDemo3 
{
    public static void main(String[] args) 
    {
        //建立4个售票线程
        TicketThread t1 = new TicketThread();
        TicketThread t2 = new TicketThread();
        TicketThread t3 = new TicketThread();
        TicketThread t4 = new TicketThread();

        //调用start方法,启动4个线程,调用run方法
        t1.start();
        t2.start();
        t3.start();
        t4.start();


    }
}
运行结果1

Ticket 30 is saled by Thread-1
Ticket 30 is saled by Thread-3
Ticket 30 is saled by Thread-0
Ticket 30 is saled by Thread-2
Ticket 29 is saled by Thread-0
Ticket 29 is saled by Thread-3
Ticket 29 is saled by Thread-1
Ticket 28 is saled by Thread-3
Ticket 28 is saled by Thread-0
Ticket 29 is saled by Thread-2
Ticket 27 is saled by Thread-0
Ticket 27 is saled by Thread-3
Ticket 28 is saled by Thread-1
Ticket 26 is saled by Thread-3
Ticket 26 is saled by Thread-0
Ticket 28 is saled by Thread-2
Ticket 25 is saled by Thread-0
Ticket 25 is saled by Thread-3
Ticket 27 is saled by Thread-1
Ticket 24 is saled by Thread-3
Ticket 24 is saled by Thread-0
Ticket 27 is saled by Thread-2
Ticket 23 is saled by Thread-0
Ticket 23 is saled by Thread-3
Ticket 26 is saled by Thread-1
Ticket 22 is saled by Thread-3
Ticket 22 is saled by Thread-0
Ticket 21 is saled by Thread-0
Ticket 26 is saled by Thread-2
Ticket 20 is saled by Thread-0
Ticket 21 is saled by Thread-3
Ticket 25 is saled by Thread-1
Ticket 20 is saled by Thread-3
Ticket 19 is saled by Thread-0
Ticket 25 is saled by Thread-2
Ticket 18 is saled by Thread-0
Ticket 19 is saled by Thread-3
Ticket 24 is saled by Thread-1
Ticket 18 is saled by Thread-3
Ticket 17 is saled by Thread-3
Ticket 16 is saled by Thread-3
Ticket 15 is saled by Thread-3
Ticket 14 is saled by Thread-3
Ticket 13 is saled by Thread-3
Ticket 12 is saled by Thread-3
Ticket 11 is saled by Thread-3
Ticket 10 is saled by Thread-3
Ticket 9 is saled by Thread-3
Ticket 8 is saled by Thread-3
Ticket 17 is saled by Thread-0
Ticket 24 is saled by Thread-2
Ticket 23 is saled by Thread-2
Ticket 22 is saled by Thread-2
Ticket 21 is saled by Thread-2
Ticket 20 is saled by Thread-2
Ticket 16 is saled by Thread-0
Ticket 15 is saled by Thread-0
Ticket 14 is saled by Thread-0
Ticket 7 is saled by Thread-3
Ticket 23 is saled by Thread-1
Ticket 22 is saled by Thread-1
Ticket 21 is saled by Thread-1
Ticket 6 is saled by Thread-3
Ticket 13 is saled by Thread-0
Ticket 19 is saled by Thread-2
Ticket 12 is saled by Thread-0
Ticket 11 is saled by Thread-0
Ticket 10 is saled by Thread-0
Ticket 9 is saled by Thread-0
Ticket 8 is saled by Thread-0
Ticket 7 is saled by Thread-0
Ticket 6 is saled by Thread-0
Ticket 5 is saled by Thread-0
Ticket 5 is saled by Thread-3
Ticket 4 is saled by Thread-3
Ticket 3 is saled by Thread-3
Ticket 2 is saled by Thread-3
Ticket 1 is saled by Thread-3
Ticket 20 is saled by Thread-1
Ticket 4 is saled by Thread-0
Ticket 3 is saled by Thread-0
Ticket 2 is saled by Thread-0
Ticket 18 is saled by Thread-2
Ticket 1 is saled by Thread-0
Ticket 19 is saled by Thread-1
Ticket 18 is saled by Thread-1
Ticket 17 is saled by Thread-1
Ticket 16 is saled by Thread-1
Ticket 15 is saled by Thread-1
Ticket 17 is saled by Thread-2
Ticket 16 is saled by Thread-2
Ticket 15 is saled by Thread-2
Ticket 14 is saled by Thread-1
Ticket 13 is saled by Thread-1
Ticket 12 is saled by Thread-1
Ticket 11 is saled by Thread-1
Ticket 10 is saled by Thread-1
Ticket 9 is saled by Thread-1
Ticket 8 is saled by Thread-1
Ticket 14 is saled by Thread-2
Ticket 13 is saled by Thread-2
Ticket 12 is saled by Thread-2
Ticket 11 is saled by Thread-2
Ticket 10 is saled by Thread-2
Ticket 9 is saled by Thread-2
Ticket 7 is saled by Thread-1
Ticket 8 is saled by Thread-2
Ticket 7 is saled by Thread-2
Ticket 6 is saled by Thread-1
Ticket 5 is saled by Thread-1
Ticket 4 is saled by Thread-1
Ticket 6 is saled by Thread-2
Ticket 3 is saled by Thread-1
Ticket 5 is saled by Thread-2
Ticket 2 is saled by Thread-1
Ticket 1 is saled by Thread-1
Ticket 4 is saled by Thread-2
Ticket 3 is saled by Thread-2
Ticket 2 is saled by Thread-2

结果显示:1张票被卖了4次。
改正方法:利用static 的共享特点

代码2
//改正后的代码
//建立售票线程类
class TicketThread extends Thread
{
    //私有化票额,并利用static共享票号
    private static int ticket =30 ;

    //覆盖run方法
    public void run()
    {
            //建立一个循环售票,当票售完即停止
            while(ticket > 0)
            {
                //打印当前线程对象售出的票号
                System.out.println("Ticket "+ticket+" is saled by "+Thread.currentThread().getName());
                //票号减一
                ticket--;
            }
    }
}

class ThreadDemo3 
{
    public static void main(String[] args) 
    {
        //建立4个售票线程
        TicketThread t1 = new TicketThread();
        TicketThread t2 = new TicketThread();
        TicketThread t3 = new TicketThread();
        TicketThread t4 = new TicketThread();

        //调用start方法,启动4个线程,调用run方法
        t1.start();
        t2.start();
        t3.start();
        t4.start();


    }
}
运行结果2:

Ticket 30 is saled by Thread-1
Ticket 30 is saled by Thread-0
Ticket 30 is saled by Thread-3
Ticket 30 is saled by Thread-2
Ticket 27 is saled by Thread-3
Ticket 28 is saled by Thread-0
Ticket 24 is saled by Thread-0
Ticket 29 is saled by Thread-1
Ticket 23 is saled by Thread-0
Ticket 25 is saled by Thread-3
Ticket 20 is saled by Thread-3
Ticket 26 is saled by Thread-2
Ticket 19 is saled by Thread-3
Ticket 21 is saled by Thread-0
Ticket 22 is saled by Thread-1
Ticket 16 is saled by Thread-0
Ticket 17 is saled by Thread-3
Ticket 18 is saled by Thread-2
Ticket 13 is saled by Thread-3
Ticket 14 is saled by Thread-0
Ticket 15 is saled by Thread-1
Ticket 10 is saled by Thread-0
Ticket 11 is saled by Thread-3
Ticket 12 is saled by Thread-2
Ticket 7 is saled by Thread-3
Ticket 8 is saled by Thread-0
Ticket 9 is saled by Thread-1
Ticket 4 is saled by Thread-0
Ticket 5 is saled by Thread-3
Ticket 6 is saled by Thread-2
Ticket 1 is saled by Thread-3
Ticket 2 is saled by Thread-0
Ticket 3 is saled by Thread-1

结果仍然会有一张票被卖4次。
原因,由于是多线程运行,当t1调用run方法并执行到打印语句的时候,
其他线程抢占资源,ticket–;并没有执行。

改正方法:把ticket–;融合进打印语句。

小结:run方法里的语句不要太多。

代码3
//改正后的代码
//建立售票线程类
class TicketThread extends Thread
{
    //私有化票额,并利用static共享票号
    private static int ticket =30 ;

    //覆盖run方法
    public void run()
    {
            //建立一个循环售票,当票售完即停止
            while(ticket > 0)
            {
                //打印当前线程对象售出的票号,并立即减少1张票额
                System.out.println("Ticket "+(ticket--)+" is saled by "+Thread.currentThread().getName());

            }
    }
}

class ThreadDemo3 
{
    public static void main(String[] args) 
    {
        //建立4个售票线程
        TicketThread t1 = new TicketThread();
        TicketThread t2 = new TicketThread();
        TicketThread t3 = new TicketThread();
        TicketThread t4 = new TicketThread();

        //调用start方法,启动4个线程,调用run方法
        t1.start();
        t2.start();
        t3.start();
        t4.start();


    }
}
运行结果3:

Ticket 29 is saled by Thread-2
Ticket 27 is saled by Thread-2
Ticket 26 is saled by Thread-2
Ticket 25 is saled by Thread-2
Ticket 30 is saled by Thread-1
Ticket 23 is saled by Thread-1
Ticket 22 is saled by Thread-1
Ticket 29 is saled by Thread-3
Ticket 28 is saled by Thread-0
Ticket 20 is saled by Thread-3
Ticket 18 is saled by Thread-3
Ticket 17 is saled by Thread-3
Ticket 21 is saled by Thread-1
Ticket 15 is saled by Thread-1
Ticket 14 is saled by Thread-1
Ticket 13 is saled by Thread-1
Ticket 12 is saled by Thread-1
Ticket 11 is saled by Thread-1
Ticket 24 is saled by Thread-2
Ticket 9 is saled by Thread-2
Ticket 8 is saled by Thread-2
Ticket 7 is saled by Thread-2
Ticket 10 is saled by Thread-1
Ticket 16 is saled by Thread-3
Ticket 19 is saled by Thread-0
Ticket 4 is saled by Thread-3
Ticket 2 is saled by Thread-3
Ticket 1 is saled by Thread-3
Ticket 5 is saled by Thread-1
Ticket 6 is saled by Thread-2
Ticket 3 is saled by Thread-0

现在结果正常了,但是有一个问题。
staitc在内存中呆的时间太长了,不利于资源的利用。

创建线程的第二种方式

通过查阅API发现:
创建线程的另一种方式是声明实现Runnable接口的类

步骤:
1、创建一个类并实现Runnable接口
2、覆盖Runnable中的run方法,把线程的代码存放在run的方法体
3、初始化该类。例如Ticket t =new Ticket();
4、创建线程,并把该类的对象传递给线程。例如:Thread t1 =Thread(t);
这是因为在Thread类中有这么一个构造函数Thread(Runnable target)
5、调用start方法,启动线程并调用run方法。

代码
//创建线程的另一种方式,声明实现Runnable接口的类Ticket
class Ticket implements Runnable
{
    //私有化票额,因为接口是共享的,所以不需要static修饰,提高了效率
    private  int ticket =30 ;

    //覆盖Runanble接口的run方法,把线程执行的代码存入
    public void run()
    {
            //建立一个循环售票,当票售完即停止
            while(ticket > 0)
            {
                //打印当前线程对象售出的票号,并立即减少1张票额
                System.out.println("Ticket "+(ticket--)+" is saled by "+Thread.currentThread().getName());

            }
    }
}

class ThreadDemo3 
{
    public static void main(String[] args) 
    {
        //创建一个Ticket对象,注意这里和第一种创建线程方法的不同。
        //这里创建的是票的对象,第一种方法,创建的是售票线程的对象。
        //在这里就共享了票额。
        Ticket t =new Ticket();

        //利用构造函数Thread(Runnable target)创建4个售票线程
        //这里利用了多态的形式,建立了接口的引用
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        //调用start方法,启动线程并调用run方法,开始售票
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}
运行结果:

Ticket 30 is saled by Thread-2
Ticket 27 is saled by Thread-3
Ticket 28 is saled by Thread-1
Ticket 29 is saled by Thread-0
Ticket 24 is saled by Thread-1
Ticket 25 is saled by Thread-3
Ticket 26 is saled by Thread-2
Ticket 20 is saled by Thread-2
Ticket 21 is saled by Thread-3
Ticket 22 is saled by Thread-1
Ticket 17 is saled by Thread-1
Ticket 16 is saled by Thread-1
Ticket 23 is saled by Thread-0
Ticket 15 is saled by Thread-1
Ticket 18 is saled by Thread-3
Ticket 12 is saled by Thread-3
Ticket 19 is saled by Thread-2
Ticket 11 is saled by Thread-3
Ticket 13 is saled by Thread-1
Ticket 14 is saled by Thread-0
Ticket 7 is saled by Thread-0
Ticket 8 is saled by Thread-1
Ticket 9 is saled by Thread-3
Ticket 10 is saled by Thread-2
Ticket 4 is saled by Thread-3
Ticket 5 is saled by Thread-1
Ticket 6 is saled by Thread-0
Ticket 1 is saled by Thread-1
Ticket 2 is saled by Thread-3
Ticket 3 is saled by Thread-2

结果显示:创建线程成功,票额售票成功!需求满足!

小结:

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

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

两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值