码迷,mamicode.com
首页 > 编程语言 > 详细

深入浅出Java多线程

时间:2016-04-18 15:05:19      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:

进程与线程

进程:程序(任务)的执行过程(动态的),持有资源(共享内存,共享文件)和线程

如在我们电脑上的QQ,如果只是放在那里,并不是进程,只有当你点击它运行后,才启动了一个进程。

线程:如QQ,可以文字聊天,同时首发文件,这就是2个线程。

线程是系统中最小的执行单元,同一个进程可以拥有多个线程,线程共享进程的资源。

线程的交互:互斥(竞争)与同步(合作)

如,在同一个班级中,每个同学都是一个线程,大家共享公共资源如桌椅,黑板,学习资料等。同学间可以交流,关系有互斥与同步。如当同学A与同学B同时向使用某个学习资料时,就产生了互斥,需要一个一个使用;当学校组织文艺汇演时,需要同学间互相合作,才能表演优秀的节目。

 

 Java线程之初体验

  • Java对线程的支持
    • Thread类与Runnable接口,都有run()方法
  • 线程的创建和启动
  • 线程常用方法
    • 技术分享
  •  

以隋唐英雄演绎这个实战项目来进一步了解Java的多线程

  • 根据故事梗概,我们需要“军队-ArmyRunnable”,“英雄人物-KeyPersonThread”,“舞台-Stage”这三个类;
  • 技术分享
    /**
     * 军队线程
     * 模拟作战双方的行为
     * @author
     *
     */
    public class ArmyRunnable implements Runnable {
        //volatile(可见性 JMM, happens-before原则)保证线程可以正确读取其他线程写入的值
        volatile boolean keepRunning = true;
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(keepRunning) {
                //发动5连击
                for(int i=0; i<5; i++) {
                    System.out.println(Thread.currentThread().getName() + 
                            "进攻对方第[" + i + "]击");
                    //让出了CPU时间,下次该谁进攻还不一定呢!
                    Thread.yield();
                }
            }
            System.out.println(Thread.currentThread().getName() + "结束了战斗!");
        }
    
    }
    
    
    public class KeyPersonThread extends Thread {
        public void run() {
            System.out.println(Thread.currentThread().getName() + "开始了战斗!");
            
            for(int i=0; i<10; i++) {
                System.out.println(Thread.currentThread().getName() + "左突右杀,攻击隋军。。。");
            }
            
            System.out.println(Thread.currentThread().getName() + "结束了战斗!");
        }
    }
    
    
    /**
     * 隋唐演义的大戏舞台
     * @author
     *
     */
    public class Stage extends Thread {
        public void run() {
            
            System.out.println("欢迎观看隋唐演义");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println("大幕徐徐打开");
            
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            
            System.out.println("话说隋朝末年,隋军与农民起义军杀得昏天黑地...");
            
            
            ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable();
            ArmyRunnable armyTaskOfRevolt = new ArmyRunnable();
            
            //使用Runnable接口启动线程
            Thread armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty, "隋军");
            Thread armyOfRevolt = new Thread(armyTaskOfRevolt, "起义军");
            
            //启动线程,让双方军队开始作战
            armyOfSuiDynasty.start();
            armyOfRevolt.start();
            
            //舞台线程休眠,大家专心观看军队的厮杀
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            
            System.out.println("正当双方激战正酣,半路杀出了个程咬金");
            Thread mrCheng = new KeyPersonThread();
            mrCheng.setName("程咬金");
            System.out.println("程咬金的理想就是结束战争,使百姓可以安居乐业!");
            
            //军队停止作战,停止线程的方法
            armyTaskOfSuiDynasty.keepRunning = false;
            armyTaskOfRevolt.keepRunning = false;
            
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            //历史大戏留给关键人物
            mrCheng.start();
            try {
                mrCheng.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            System.out.println("战争结束,人民安居乐业,程先生实现了积极的人生梦想,为人民作出了贡献");
            System.out.println("谢谢观看隋唐演义,谢谢!");
            
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new Stage().start();
        }
    
    }
    View Code

     

  • 如何正确的停止线程
    • stop()方法就是一个不正确的停止线程的方法;它会使线程戛然而止,我们不知道它完成了什么工作,没有完成什么工作,因此是错误的。
    • 使用退出旗标:如上面的例子中keepRunning就是一个结束标志。
    • interrupt()方法:初衷并不是用于停止线程

 

   Java线程交互

  • 消失的能量
    • 什么是争用条件(Race Condition)
      • 当多个线程同时访问同一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据破坏(corrupted),这种现象称为争用条件。
      • 技术分享
      • 如上图所示,当某个时间片时,线程1获得了CPU时间,从主存中读取了energyBox[to]的值,然后加上500,但还没有写回内存时,CPU时间耗尽;然后线程2抢到了CPU,读取的energyBox[to]的值仍为5000,然后它操作加上900,并写回内存5900,然后CPU时间耗尽。而下面又是线程1获得了时间片,将它上面计算完的5500写入内存,导致最终内存中存储的值为5500.而通过线程1和线程2的修改,最终写入内存的energyBox[to]的值应该为6400才是正确的!经过这样的方式运行,就发生了能量不守恒的结果。
      • 那么,如何修改代码,使能量变得守恒呢?
        • 互斥与同步,得到线程正确的进行交互。
        • 互斥:关键数据在同一时间只能被一个线程访问。实现:synchronized(intrinsic lock)
        • 同步:由于资源某些条件不满足,导致所有的线程陷入等待状态;而当访问资源的条件满足后,会唤醒所有的线程,进入互斥状态。实现:wait()/notify()/notifyAll()——都是Object对象的方法。
        • wait()/notify()/notifyAll()不是在同一个线程的同一次操作中执行的。因为同步是指多个线程之间的同步,只有一个线程的话是不需要同步的!!
        • 当一个线程要访问一个临界区(Critical Section)时,首先要获得该临界区的锁,当获得了锁后去判断是否满足获得该资源的条件,当条件不满足时,将释放锁(使得其他线程可以进入临界区),并进入该锁对象上的等待(wait())队列中等待。当其它线程使用完了临界区后,将告知(notifyAll())所有等待队列中的线程:目前临界区内的条件有变化,大家可以开始竞争锁对象。

 

 

    要点回顾

  • 如何创建线程及线程的基本操作;
  • 可见性及volatile关键字;
  • 争用条件;
  • 线程的互斥synchronized;
  • 线程的同步wait/notifyAll();

 

  扩展

  • Java Memory Mode
    • JMM描述了Java线程如何通过内存进行交互
    • happens-before原则
    • synchronized, volatile & final
  • Locks & Condition
    • Java锁机制和等待条件的高层实现
    • java.util.concurrent.locks
  • 线程的安全性
    • 原子性与可见性
    • java.util.concurrent.atomic
    • synchronized & volatile
    • DeadLocks
  • 多线程常用的交互模型
    • Producer-Consumer模型
    • Read-Write Lock模型
    • Future模型
    • Worker Thread模型
  • Java5中并发编程工具
    • java.util.concurrent
    • 线程池ExcecutorService
    • Callable & Future
    • BlockingQueue

深入浅出Java多线程

标签:

原文地址:http://www.cnblogs.com/little-YTMM/p/5404126.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!