黑马程序员——多线程


------- 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 String name;

    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 String name;

    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

黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值