`
wtt2312
  • 浏览: 14078 次
  • 性别: 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培训期待与您交流!-----

分享到:
评论

相关推荐

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

    NULL 博文链接:https://huangminwen.iteye.com/blog/1157983

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

    NULL 博文链接:https://lvwenwen.iteye.com/blog/1470696

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

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

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

    当一个进程中线程有多个时,是多线程。  为什么要用多线程  1,让计算机"同时"做多件事情,节约时间。  2,后台运行程序,提高程序的运行效率.。  3,多线程可以让程序"同时"处理多个事情。  4,...

    黑马程序员_张孝祥_Java多线程与并发库 视频+代码+资料

    黑马程序员_张孝祥_Java多线程与并发库,视频+代码+资料

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

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

    黑马程序员 安卓学院 万元哥项目经理 分享220个代码实例

    |--利用FinalHttp实现多线程断点续传 |--加密之MD5 |--动画Animation详解 |--动画之view左右抖动 |--动画之移动动画 |--动画之组合动画 |--动画之缩放动画ScaleAnimation |--反序列化对象 |--发送短信 读天气 调音量...

    java拼图游戏源码.zip

    这是一个java写的拼图游戏,用了swing、多线程等知识,可以设置行数列、列数、还有使用多线程写的游戏动画,拼图的图块具有磁贴设计,代码封装性较强,容易移植,纯原创。

    图解java多线程设计模式

    日本资-深技术作家、《程序员的数学》作者结城浩执笔,264张图表(UML类图、时序图、Timethreads图等)穿插文中,通过类比手法和浅显的语言,逐一讲解与多线程和并发处理相关的12种设计模式。每章附带练习题和答案,...

    图解java多线程设计模式2017年8月最新版

    精选12种与多线程和并发处理相关的设计模式 264张图表 + 300段Java示例程序 = 轻松学习多线程编程 日本经典多线程入门书,原版长销11年! 本书适合以下读者阅读 a.对多线程感兴趣的人 b.对Java编程感兴趣的人 c.对...

    传智播客_Java培训_毕向东_Java基础[05-多线程]

    传智播客_Java培训_毕向东_Java基础[05-多线程]系黑马程序员_毕向东_Java基础视频教程

    拼图游戏 (源码+所有文件)

    萌新做的一个简单的Java拼图游戏 启动类:pers.sept.jigsaw1.swing下的...多线程。 下拉列表选择数字可以切换关卡图片,最后的“+”,可以添自己的图片到关卡中。 设有背景音乐 有一键通过按钮 等等,块下载去看看吧。

    java并发库高级应用源码--张孝祥

    java并发库thread使用,传统线程技术、定时器技术、线程互斥技术,同步通讯技术、多线程共享数据、并发库应用,线程锁技术,阻塞锁、阻塞队列,线程池等应用

    《Java基础案例教程(第2版)》课后习题答案1

    第1章 Java开发入门一.填空题1. 面向对象,SUN 2. JavaSE,JavaEE,JavaME3.面向对象、跨平台性、支持多线程4. JDK5.bin

    图解java多线程设计模式 2017年8月最新版

    这本书的pdf文件有162M,是最新版高清的pdf,网上原书售价60多元,这里提供的附件是百度云的链接地址。

    学成在线-分布式任务视频处理

    2.适用于黑马程序员Java企业级实战开发《学成在线》微服务项目,基于SpringCloud、SpringCloudAlibaba技术栈开发。 3.采用xxl-job技术。 4.步骤概要: 4.1 作业分片方案 4.2 保证任务不重复执行 4.3 业务流程 5....

    JAVA核心知识点整理.pdf

    给大家分享一篇我在学习java过程中...包含常见的面试题:JVM、Java集合、多线程并发、java基础、SSM框架原理、微服务、Netty和RPC、网络、日志、算法、数据结构、加密、分布式算法、机器学习、大数据等知识点,都是干货

    黑马JVM学习笔记二

    title: 黑马JVM学习笔记二 date: 2020-01-13 1:00:00 ...线程是私有的,多线程之间分别有各自的程序计数器记录对应线程的执行位置 程序计数器是Java虚拟机规范中唯一一个不会存在内存溢出的区(堆和栈等会出现内存溢

    mfc教程(word版)

    4.4.3.2 命令消息的派发和消息的多次处理 67 4.4.3.3 一些消息处理类的OnCmdMsg的实现 69 4.4.3.4 一些消息处理类的OnCommand的实现 71 4.4.4 对控制通知消息的接收和处理 72 4.4.4.1 WM_COMMAND控制通知消息的处理 ...

    java7源码-Java-concurrent:Java并发编程

    黑马程序员——Java异步课程源码 plugin Lombok logback.xml 说明 课堂代码主要在 case_java8 子模块内,按章节划分, io.github.hank.java.concurrent.n2 - 同步与异步 io.github.hank.java.concurrent.n3 - Java...

Global site tag (gtag.js) - Google Analytics