美文网首页Java
java学习笔记#9-多线程

java学习笔记#9-多线程

作者: edwin1993 | 来源:发表于2018-08-11 14:51 被阅读0次

    多线程概念

    • 进程:
      进程是程序(任务)执行的过程
      进程持有资源和线程

    • 线程
      线程是系统中的最小执行单元
      一个进程有多个线程
      线程共享进程资源

    • 线程的交互:互斥&同步

    多线程示例

    Java对线程的支持体现在Thread类和Runnable接口

    通过继承Thread类实现多线程,但是这种方式有一定的局限性。因为在java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,比如学生类Student继承了person类,就无法再继承Thread类创建的线程。
    为了克服这种弊端,Thread类提供了另外一种构造方法Thread(Runnable target),其中Runnable是一个接口,它只有一个run()方法。

    package Base.Multprocess;
    
    /**
     * Created by Edwin_1993 on 2018/8/10.
     */
    public class ThreadExample extends Thread {
        public void run(){
            System.out.println(getName() + " threadExample");
            int count = 0;
            boolean keepRunning = true;
            while(keepRunning){
                System.out.println((getName()+ " num:" + ++count));
    
                if (count == 100){
                    keepRunning = false;
                }
                if (count%10 == 0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            System.out.println(getName()+ " end");
        }
    
        
        public static void main(String args[]){
            Thread thread = new ThreadExample();
            thread.setName("ThreadExample");
    
            thread.start();
    
            Thread runnableThread = new Thread(new RunnableExample(),"Ms Runnable");
            runnableThread.start();
        }
    }
    
    class RunnableExample implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " RunnableExample");
            int count = 0;
            boolean keepRunning = true;
            while (keepRunning) {
                System.out.println((Thread.currentThread().getName() + " num:" + ++count));
    
                if (count == 100) {
                    keepRunning = false;
                }
                if (count % 10 == 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    多线程的停止方式

    • stop()方法
      这是一个错误的方法,会使得线程戛然而止,不知道完成了哪些以及如何清理。

    • interrupt方法
      方法初衷并不是停止线程
      下方代码无法正确结束线程。

    package Base.Multprocess;
    
    /**
     * Created by Edwin_1993 on 2018/8/11.
     */
    public class WrongWayStopThread extends Thread {
        public static void main(String args[]){
            WrongWayStopThread wrongWayStopThread = new WrongWayStopThread();
            System.out.println("Thread starting ...");
            wrongWayStopThread.start();
    
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread interrupting ...");
            wrongWayStopThread.interrupt();
    
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread ending ...");
        }
    
        public void run(){
            while (true){
    //        while (!this.isInterrupted()){
                System.out.println("Thread is running ...");
                long time = System.currentTimeMillis();
                while((System.currentTimeMillis() - time) < 1000){
    
                }
            }
        }
    }
    
    

    上述run方法改写后相当于使用了退出标志。

        public void run(){
    //        while (true){
            while (!this.isInterrupted()){
                System.out.println("Thread is running ...");
                long time = System.currentTimeMillis();
                while((System.currentTimeMillis() - time) < 1000){
    
                }
            }
        }
    

    使用sleep()方法,线程进入了阻塞状态,此时再调用interrupte方法会使得interrupt状态被清除,使得this.isInterrupted()无效,且使得sleep方法被中断:InterruptedException 。

        public void run(){
    //        while (true){
            while (!this.isInterrupted()){
                System.out.println("Thread is running ...");
                long time = System.currentTimeMillis();
                while((System.currentTimeMillis() - time) < 1000){
    
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    • 使用退出标志:
      如下方代码中的keepRunning标志
    package Base.Multprocess;
    
    /**
     * Created by Edwin_1993 on 2018/8/11.
     */
    public class ArmyRunnable implements Runnable{
    //    volatile 保证了线程可以正确读取其它线程写入的值
    //    一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
    //
    //    1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
    //
    //    2)禁止进行指令重排序
        volatile boolean keepRunning = true;
    
        @Override
        public void run() {
            while (keepRunning){
                for(int i = 0;i <5;i++){
                    System.out.println(Thread.currentThread().getName() + "attack["+i+"]");
    //                t
                    Thread.yield();
                }
            }
            System.out.println(Thread.currentThread().getName() + "end attack");
        }
    }
    
    

    线程交互

    • 争用条件:
      当多个线程同时访问同一数据的时候,每个线程都在尝试操作该数据,从而导致数据被破环,这种情况叫做争用条件。

    • 互斥:
      互斥的实现:synchronized(intrinsic lock)
      synchronized块中的代码,通过获取lockObj锁来执行。

    private final Object lockObj = new Object();
    
    
    public void transfer(int from ,int to, double amount){
    
    //        通过synchronized进行互斥
            synchronized (lockObj){
    //            if (energyBoxes[from] < amount){
    //                System.out.println("not enought energy");
    //                return;
    //            }
    
    //            满足while条件时,任务被阻挡,不去竞争CPU资源。
                while (energyBoxes[from] < amount){
                    try {
                        lockObj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(Thread.currentThread().getName());
                energyBoxes[from] -= amount;
                System.out.printf("从 %d 转移 %10.2f 单位能量到 %d",from,amount,to);
                energyBoxes[to] += amount;
                System.out.printf("能量总合: %10.2f", getTotalEnergy());
            }
    
    //        非互斥模式
    //        if (energyBoxes[from] < amount){
    //            System.out.println("not enought energy");
    //            return;
    //        }
    //        System.out.print(Thread.currentThread().getName());
    //        energyBoxes[from] -= amount;
    //        System.out.printf("从 %d 转移 %10.2f 单位能量到 %d",from,amount,to);
    //        energyBoxes[to] += amount;
    //        System.out.printf("能量总合: %10.2f", getTotalEnergy());
    
    //        唤醒所有在lockObj上等待的线程。
            lockObj.notifyAll();
        }
    
    • 同步
      同步的实现:wait()/notify()/notifyAll()
      这些方法都是object类的方法。

    上述代码中
    当运行条件不满足的时候,通过lockobj.wait()来将线程放入Wait set
    当某一条线程顺利执行完成时,通过lockobj.notifyAll()来唤醒所有的等待线程。

    相关文章

      网友评论

        本文标题:java学习笔记#9-多线程

        本文链接:https://www.haomeiwen.com/subject/seslbftx.html