`
wtt2312
  • 浏览: 14828 次
  • 性别: Icon_minigender_2
最近访客 更多访客>>
社区版块
存档分类
最新评论

黑马程序员---多线程

 
阅读更多

                                   ----- http://www.itheima.comjava培训、android培训期待与您交流!-----

       在我们玩电脑时,我们可以同时打开多个应用程序,并可以一边听歌,一边玩游戏,还可以浏览网站,打文件夹。在我们看来,电脑上的这么多应用程序是同时运行 的,其实,不然。CPU在某一时刻只能运行一个应用程序,这些程序看起来在同时运行,其实他们在做着飞速的转换,只是时间及其短,短的我们不能感觉到他们 的停止。而双核的电脑运行快,性能好。而这是怎么做到的呢?首先我们了解一些概念:
       进程是正在执行的程序(QQ、stormplayer等)。每个进程执行都有一个执行顺序,该执行顺序是一个执行路径,也可以叫控制单元。
       线程是进程中的一个独立的控制单元。线程在控制着进程的执行。
       一个进程中至少有一个线程。 在我们启动JVM时,不止有一个线程,还有垃圾回收机制(GC)这个线程(在对内存中)。

 

1、创建线程

 

创建线程的方式有两种:继承Tread类、实现Runnable接口
A、继承Tread类

步骤:(1)定义一个类并继承Thread类
           (2)复写Thread类中的run方法
           (3)调用线程的start方法
         

 class MyThread  extends Thread {
                    public void run()
                        {
                                for (int x=0;x<30 ; x++)
                                    {
                                            System.out.println("demo run------"+x);
                                    }                   }         }
         class ThreadDemo {
                public static void main(String[] args) {
                        //新建对象(线程)
                       ThreadDemo td = new ThreadDemo();
                      //调用start方法,开启线程,并运行run方法,  运行结果:demo run---和hello world---交替打印
                         td.start();
                         //若调用run方法:
                        //只是对象调用方法并没有运行实现线程间的交替   运行结果:demo run--- 打印完 hello world---再打印
                         //td.run();
                           for (int x =0;x<1000;x++){
                                    System.out.println("hello world---"+x);
                                    }                 }             }

 
这两个线程在切换着执行,谁先获得CPU的执行权谁先执行。 
线程的一个特性:随机性
为什么要覆盖run方法?
run方法用于存储线程要运行的自定义代码
start方法的作用:启动线程,调用run方法


线程的运行状态
线程被创建-------运行(start方法)--------冻结(放弃执行资格)(sleep和wait、notify方法)
在运行和冻结状态时,也可能存在阻塞(具有运行资格但没有执行权)和消亡状态(stop或run结束)

获取线程的对象以及名称:Thread.currentThread()  获取当前线程对象
                                           getName():获取线程名称


B、实现Runnable接口:
步骤: (1)定义一个类并实现Runnable接口
           (2)覆盖Runnable接口中的run方法
           (3)通过Thread类建立线程对象
           (4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
           (5)调用Thread类的start方法开启线程,并调用Runnable接口的run方法
实现方式和继承方式的区别:
                实现方式的好处:避免了单继承的局限性
                继承Thread类:线程代码存放在Thread 子类的run方法中
                实现Runnable接口:线程代码存放在接口的子类的run方法中
例子:卖票程序(多线程) 多个窗口卖票

class Ticket implements Runnable
{
    private int tick = 50;
    public void run()
    {
        while(true)
            if (tick>0)
            {
                System.out.println(Thread.currentThread().getName()+"---sale:---"+tick--);
            }    }     }
class TicketDemo
{
    public static void main(String[] args)
    {
        Ticket t = new Ticket();//创建对象

        Thread t1 = new Thread(t);//创建一个线程(对象)
        Thread t2 = new Thread(t);//t:run方法所属对象
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);


        t1.start();
        t2.start();
        t3.start();
        t4.start();
        /*
        Ticket t1 = new Ticket("第一个窗口");并没有创建线程
        Ticket t2 = new Ticket("第二个窗口");
        Ticket t3 = new Ticket("第三个窗口");
        Ticket t4 = new Ticket("第四个窗口");

        t1.start();
        线程已经开启,再开启无意义
        t2.start();
        t3.start();
        t4.start();
        */
    }
}

 

 

2、多线程的安全问题

在上面的售票的例子中,我们知道,程序一共创建了4个线程:Thread-0Thread-1Thread-2Thread-3。线程具有随机的特点,假设现在票数为1,而线程0抢到了CPU的执行权,此时,判断票数不为0,但线程0还未判断完,执行权就让线程1抢去了,这时线程0就处于等待状态不再向下执行。而线程1还未判断完线程2就抢到了执行权,依次类推,线程0123都处于等待状态。当然,这时线程0又抢到了执行权,继续向下执行,tick = 1;同样线程1抢到了执行权,判断后继续执行,tick = 0;根据实际情况,票数不可能为0,所以这时,程序就出现了问题,票已经卖完了,但是线程还有可能继续,票数出现了负数。

由于票数是共享数据,是这四个卖票窗口同时售。

所以,这时,我们就要考虑线程的安全问题。

出现安全问题的原因:

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

如何解决呢?

因为线程在对语句执行时没有执行完就被其他线程抢去了执行权,所以,我们可以控制一个线程在确保将多条语句执行完后再让其他线程获得执行权。

java中,解决多线程的安全问题则使用关键字synchronized

同步代码块:

synchronized(对象){需要被同步的代码}

 

3、线程同步

   所谓线程同步,我所理解的就是,一个线程在执行完后才将执行权释放出去,留给其他的线程执行。

   在卖票例子中,如果给判断语句加上同步(并不是run方法中代码都加同步,下面会讲到加同步的前提),那么,当其中一个线程获得执行权后,进行判断,在判断前,会先将锁(这里的锁是对象)的状态改为锁上(这里的状态一般用和 1标识),那么这个程序的其他线程就进不来,直到该线程执行完,才将执行权释放(在释放之前,会把锁的状态改变)

(1)同步的前提:

必须是两个或两个以上的线程

必须保证多个线程使用同一个锁

且同步中只能有一个线程在运行

(2) 同步的好处:解决了多线程的安全问题

   同步的弊端:多个线程需要判断锁,较为耗费资源。(防盗门例子)

 

(3)同步函数

同步的方式有两种:同步代码块和同步函数(让函数具有同步性)

同步代码块是将要进行同步的代码(当数据被共享时)封装在synchronized关键字中。

而在封装功能时,也可能会有共享数据,当然也可以用同步代码块,但,同步代码块的代码有些繁琐,还要缩进,所以,只要在函数上用synchronized关键字就可以了(要保证满足同步的两个前提),比较简洁,又能保证多线程的安全性。

如何定义同步函数?要明确多线程运行代码、明确共享数据(一般是成员)、明确多线程运行代码中那些代码操作共享数据。

同步函数的锁:this

 

(4)静态同步函数的锁

静态同步方法使用的锁是该方法所在类的字节码文件对象。类名.class

静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。静态在类加载的时候就已经进内存,即优先于主函数存在了。

 

(5)单例设计模式(参见博客 黑马程序员---单例设计模式)

 

(6)死锁

死锁就是同步中嵌套同步。比如,我们在同一个类中定义一个同步函数(将需要同步的代码封装成函数)和一个同步代码块,同步函数使用的锁是this,同步代码块使用的锁是任意对象(这里不考虑其他情况),如果在同步代码块中调用同步函数,那么,这时同步代码块中就嵌套了同步函数,且他们使用的锁不是同一个,这时就会发生死锁。

 

4、线程间通信

在上面的卖票小程序中,多个线程只是对同一个动作进行操作,即多个线程同时进行卖票的动作。而线程间通信,是指多个线程操作同一个资源,但操作动作不同。

模拟一个生产车间,当生产一个物品,假如就消费一个,那么,这时,生产者和消费者就在同时操作这个物品,但一个是生产一个是消费。他们(多个线程)操作的是同一个资源,但操作的动作不同,这就是线程间的通信。在多个线程操作同一个资源时,就会出现安全问题。如,生产一个物品而被消费两次。

等待唤醒机制:

wait();当线程处于等待状态,即该线程放弃了执行资格

notify();唤醒等待的线程。

当线程处于等待状态时,该线程在线程池中,通常唤醒的是线程池中第一个等待的线程。

JDK1.5新特性:

Lock替换了synchronized

Condition封装了await()signal(),替换了wait()notify()notifyAll()

一个lock中可以有多个condition对象,实现了本方只唤醒本方的操作。

 

5、线程的其他操作

   (1)停止线程

要想停止线程,只要run方法结束就可以。

方式:

a.控制住循环

b.interrupt(): 唤醒已处于冻结状态的线程并使用改变标记的方法停止线程。

   (2)守护线程(后台线程、用户线程)

setDaemon(boolean);在启动线程前调用。如果设置为true,那么该线程结束,程序也就结束。

   (3)join

将线程加入到正在运行的程序中,其他线程(主线程)处于冻结状态,只有该线程将执行权释放,其他线程(主线程)才能获得执行权。

   (4)优先级

线程执行的顺序。优先级高则获得执行权的概率就会大。

setPriority();  设置优先级

MAX_PRIORITY   10  最大优先级

MIN_PRIORITY    1   最小优先级

NORM_PRIORITY  5   中间级

如果只设置为数字,阅读性很差,所以,一般用常量表示。

   (5)yield

Thread.yield(); 表示临时释放执行权。

 

6、实际开发中的线程

当多个程序中需要被同时执行时,这时就用到了多线程的编写(在实际开发中很常用)。通常使用匿名内部类。

public static void main(String[] args) 

{

//直接编写

for (int x = 0;x<30 ;x++ )

{

System.out.println(Thread.currentThread().getName()+x+"----for----");

}

 

//通过继承Thread类,复写其run方法,调用start方法,

new Thread(){

public void run()

{

for (int x = 0;x<30 ;x++ )

{

System.out.println(Thread.currentThread().getName()+"---thread----");

}

}

}.start();

 

//实现Runnable接口,复写run方法,建立Thread类对象,并将子类对象作为参数传递给Thread类的构造函数

//调用thread类的start方法启动线程

Runnable r = new Runnable()

{

public void run()

{

for (int x = 0;x<30 ;x++ )

{

System.out.println(Thread.currentThread().getName()+"---runnable----");

}

}

};

new Thread(r).start();

}
 

 


 


                                   ----- http://www.itheima.comjava培训、android培训期待与您交流!-----

分享到:
评论

相关推荐

    黑马程序员-Qt讲义.pdf

    Qt提供了多线程编程的支持,包括线程的基本概念介绍、多线程的使用方法和线程安全绘图等。在数据库操作方面,Qt也提供了强大的支持,包括数据库操作的基本概念、使用模型操作数据库和对数据库数据的可视化显示等。 ...

    黑马程序员-java多线程技术01

    本教程将聚焦于Java中的多线程技术,以“黑马程序员-java多线程技术01”为学习起点,探讨如何在Java中实现并管理线程。 首先,我们来理解什么是线程。线程是操作系统分配CPU时间的基本单元,一个进程中可以有多个...

    黑马程序员-tomcat集群部署文档资料

    总结,"黑马程序员-tomcat集群部署文档资料"涵盖的范围广泛,从基础的集群概念和原理,到具体的Tomcat集群配置和优化,再到高级的源码分析,对于希望提升服务器管理和运维能力的IT从业者来说是一份宝贵的参考资料。...

    黑马程序员-C#坦克大战

    这款游戏的开发涉及到多个IT领域的知识,包括图形用户界面设计、游戏逻辑编程、碰撞检测、多线程处理以及对象导向编程等。 首先,C#是一种强大的面向对象的编程语言,由微软公司开发,用于构建Windows平台上的应用...

    多线程高新(黑马程序员)

    本文将深入探讨“多线程高新”这一主题,结合黑马程序员的课程内容,来阐述多线程的核心概念、优势、实现方式以及在实际应用中的注意事项。 首先,多线程是指在一个进程中同时执行多个线程,这些线程可以共享同一...

    B站黑马程序员Python教程学习笔记.zip

    在B站黑马程序员的Python教程中,你将深入理解Python的基础概念,包括: 1. **变量与数据类型**:Python支持多种数据类型,如整型(int)、浮点型(float)、字符串(str)和布尔型(bool)。此外,还有列表(list...

    黑马程序员入学Java精华总结

    ### 黑马程序员入学Java精华总结 #### 一、Java概述与基础知识 1. **何为编程?** - 编程是指通过编写计算机能够理解的指令来解决问题或完成特定任务的过程。这些指令通常被组织成算法,并使用某种编程语言实现。...

    黑马程序员2018python爬虫课件完整版

    黑马程序员作为知名的IT教育机构,其2018年的Python爬虫课程旨在教授学员如何有效地抓取和处理网络上的信息。在这个完整的课程中,你将深入理解Python爬虫的基本原理,并学习到一系列实用的技巧。 首先,Python之...

    黑马程序员java贪吃蛇源码

    4. **多线程应用** - **游戏主线程**:负责游戏的主循环和逻辑处理。 - **GUI刷新线程**:为了保持流畅的游戏体验,GUI通常在独立的线程中刷新,避免因为更新界面导致游戏暂停。 5. **优化技巧** - **缓冲区策略...

    黑马程序员入学面试题

    实现一个多线程的卖票程序,可以使用`synchronized`关键字或显式锁来确保线程安全。 #### 52. 用代码实现List和map存储、取出数据使用泛型 使用泛型可以确保类型安全性,避免ClassCastException等类型转换异常。 #...

    黑马程序员–Java多线程讲解笔记

    Java多线程是Java编程中不可或缺的部分,它允许程序同时执行多个任务,提高了程序的效率和响应速度。本文主要探讨了多线程的概念、应用场景...因此,理解和掌握Java的多线程技术对于任何Java程序员来说都是至关重要的。

    中关村黑马程序员训练营android-4.0视频下载地址

    根据提供的信息,我们可以总结出以下关于“中关村黑马程序员训练营Android-4.0视频”的相关知识点: ### 一、概述 “中关村黑马程序员训练营Android-4.0视频”是一套针对Android开发初学者和进阶学习者的培训课程...

    传智播客.黑马程序员《Java 基础入门》课后习题答案

    1、 面向对象、跨平台性、健壮性、安全性、可移植性、多线程性、动态性等。 2、 JRE(Java Runtime Environment,Java 运行时环境),它相当于操作系统部分,提供了 Java 程序运 行时所需要的基本条件和许多 Java ...

    黑马程序员Android学习笔记

    最后,笔记可能包含一些进阶话题,如权限管理、多线程与线程池、内存管理和性能优化,还有最近版本的Android特性和最佳实践。这些内容能帮助你开发出更加高效和稳定的应用。 总而言之,《黑马程序员Android学习笔记...

    Java-IO流高级-例题 & 例题源码 & PPT教学文档(黑马程序员详细版).rar

    本资料包“Java-IO流高级-例题 & 例题源码 & PPT教学文档(黑马程序员详细版).rar”提供了一个深入学习Java IO流的全面资源,包含实例题目、源代码以及PPT教学材料,适合对Java IO有进阶需求的开发者。 1. **Java ...

    黑马程序员安卓 笔记代码(包含源码) 第76期

    【标题】"黑马程序员安卓 笔记代码(包含源码) 第76期" 提供的是安卓开发的相关学习资料,其中包含了源码,这通常意味着我们可以深入理解代码的实现细节和设计思路。作为第76期,这可能是一个长期系列教程的一部分...

    黑马程序员Android视频教程

    ### 黑马程序员Android视频教程知识点解析 #### 一、Android基础概述 - **定义与特点**:Android是一种基于Linux内核(不包括GNU组件)的开源操作系统,主要用于移动设备。它由Google公司及其领导下的开放手机联盟...

    黑马Qt讲义文件

    文档可能还会涵盖线程管理和异步操作,这对于构建高性能、多任务的应用至关重要。 "Wxpay_NATIVE_checkout.zip"可能是一个关于微信支付(WxPay)原生SDK集成的示例或教程。在Qt中集成支付接口,可以帮助开发者将...

    黑马程序员_张孝祥_Java多线程与并发库

    黑马程序员_张孝祥_Java多线程与并发库,老师讲的非常仔细,老师很有耐心.欢迎大家下载学习.

Global site tag (gtag.js) - Google Analytics