美文网首页
线程基础,线程之间的共享和协作

线程基础,线程之间的共享和协作

作者: 讲道理很没道理 | 来源:发表于2019-02-25 16:33 被阅读0次

    基础概念
    CPU 核心数和线程数的关系
    核心数:线程数 = 1:1 ,后面使用了超线程技术后--》1:2
    CPU 时间片轮转机制
    又称RR调度,会导致上下文切换
    什么是进程和线程
    进程:程序运行资源分配的最小单元,进程内部有多个线程会共享这个进程。
    线程:CPU调度的最小单位,必须依赖进程而存在。
    并发(concurrency)和并行(parallelism)
    并行:同一时刻,可以同时处理事情的能力。
    并发:于单位时间相关,在单位时间内可以处理事情的能力。

    解释:1.并行是指两个或者多个事件在同一时刻发生,而并发是指两个或者多个事件在同一时间间隔发生。
    2.并行是在不同实体上的多个事件,并发是在同一个实体上的多个事件。
    3.在一台处理器上“同时”处理多个任务。在多态处理器上同时处理多个任务。如 hadoop 分布式集群。
    所以并发编程的目标是充分利用处理器上的每一个核,以达到最高处理性能。
    并发编程的意义,好处,和注意事项
    好处:
    1.充分利用cpu 的资源
    2:加快用户响应的事件
    3:程序模块化,异步化,可以用多线程解藕。
    问题:
    1:线程共享资源,存在冲突,容易导致死锁。
    2:启动太多的线程,就会有搞垮机器的可能。

    认识JAVA里面的线程
    java 天生就是多线程的,启动一个main 就要启动最少5个线程
    上代码:

    
    /**
     * @author sxylml
     * @Date : 2019/2/25 15:35
     * @Description: java 线程,就算只启动一个main线程,JVM 也会启动其它5-6个线程
     */
    public class OnlyMain {
        public static void main(String[] args) {
    
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
    
            for (int i = 0; i < threadInfos.length; i++) {
                System.out.println(threadInfos[i].getThreadId()+"-"+ threadInfos[i].getThreadName());
            }
    
        }
    }
    

    运行结果:

    image.png

    Attach Listener :线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。

    signal dispather: 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。

    Finalizer: 用来执行所有用户Finalizer 方法的线程

    Reference Handler :它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。

    JAVA 新启动线程的三种方式:

    package com.cap1.tools;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * @author sxylml
     * @Date : 2019/2/25 15:42
     * @Description: 创建线程的三种方式DEMO
     */
    public class NewThread {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            InteriorThread useThread = new InteriorThread();
            useThread.setName("staticInteriorThread");
            useThread.start();
    
            OuterUseThread outerThread = new OuterUseThread();
            outerThread.setName("OuterUseThread");
            outerThread.start();
    
    //        继承runable 接口
            new Thread(new UseRunnable()).start();
    
    //
            UseCallable useCallable = new UseCallable();
            FutureTask futureTask = new FutureTask(useCallable);
            new Thread(futureTask).start();
    //         可以输出返回参数
            System.out.println(futureTask.get());
    
        }
    
        /**
         * 1:继承Thread 类
         *  因为非静态内部类对 main 方法而言是不直接可见的
         */
        private static class InteriorThread extends Thread {
            @Override
            public void run() {
                System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  extends Thread");
            }
        }
    
        /**
         * 2:实现Runnable 接口
         */
        private static class UseRunnable implements Runnable {
    
            @Override
            public void run() {
                System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  implements Runnable");
            }
        }
    
        /**
         *  3 实现 Callable 接口是允许有返回类型的,类型就是接口《泛型》
         */
        private static class UseCallable implements Callable<String> {
    
            @Override
            public String call() throws Exception {
                System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  implements Callable");
                return "CallableResult";
            }
        }
    
    
    }
    
    
    
    class OuterUseThread extends Thread {
        @Override
        public void run() {
            System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  extends Thread");
        }
    }
    
    

    运行结果:


    image.png

    JAVA线程的生命周期:

    image.png

    新建状态(New):当线程对象对创建后,即进入了新建状态,如: InteriorThread t = new InteriorThread();
    就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
    运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
    阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    线程的 run,start 方法

    /**
     * @author sxylml
     * @Date : 2019/2/25 16:27
     * @Description:
     */
    public class StartAndRun {
        private static class RunThread extends Thread {
            @Override
            public void run() {
                int i = 5;
                while (i > 0) {
                    // 休眠一千毫秒
                    SleepTools.ms(100);
                    System.out.println("i'm " + Thread.currentThread().getName() + " i=" + i--);
                }
            }
        }
        public static void main(String[] args) {
            Thread beCalled = new RunThread();
            beCalled.setName("beCalled");
            beCalled.run();  // 面向对象,这样直接调用run 和普通类一样 : run 归谁调用,就归那个线程,這样运行结果就是main
            beCalled.start();// 只有调用start() ,才会是线程
        }
    }
    
    
    image.png

    守护线程:

    public class DaemonThread {
    
        private static class UseThread extends Thread {
    
            @Override
            public void run() {
    
                String threadName = Thread.currentThread().getName();
                try {
                    while (!isInterrupted()) {
                        System.out.println(threadName + " extend Thread");
                        // 抛出异常
                        Thread.sleep(100);
                    }
                    // 抛出异常這代码就不执行咯
                    System.out.println(threadName + " interrupted " + isInterrupted());
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println(threadName + " try  interrupted " + isInterrupted());
                    Thread.currentThread().interrupt();
                } finally {
                    // 是守护线程的的情况,不一定执行
                    System.out.println("-------------finally -----------------");
                }
    
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
    
            UseThread useThread = new UseThread();
            // 守护线程 和主线程共死,finally不能保证一定执行
            useThread.setDaemon(true);
            useThread.start();
            Thread.sleep(1000);
            // 发送中断通知
            useThread.interrupt();
        }
    }
    
    

    如何正确的终止线程

    1:线程自然终止:自然执行完毕或抛出未处理异常
    stop(),resume(),supende() 已经不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致死锁。

    2:调用interrupt() 方法中断一个线程,并不是强行关闭這个线程,只是跟這个线程打个招呼,讲线程的中断标志设置为true,线程是否中断,由线程本身决定。
    isInterrupted() 判断当前线程是否处于中断状态。
    static 方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false.
    方法如果抛出interruptedException ,线程的中断标志位会被复位或成false ,如果确实是需要中断线程,要求我们自己在catch 语句块里再次调用interrupt().

    
    /**
     * @author sxylml
     * @Date : 2019/2/25 15:52
     * @Description: 如何正确的中断线程
     */
    public class EndThread {
    
        private static class UseThread extends Thread {
    
            public UseThread(String name) {
                super(name);
    
            }
    
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
    //             不是中断的时候,就循环执行
                while (!isInterrupted()) {
    //                当没有向线程发送中断请求,这执行循环里面的值
                    System.out.println(threadName + " is run in while !  in interrupt flag is " + this.isInterrupted());
                }
    //               当发送了中断请求,并且中断标识改变了,则退出循环
                System.out.println(threadName + " is run out while !  in interrupt flag is " + this.isInterrupted());
            }
        }
    
    
        public static void main(String[] args) {
            Thread endThread = new UseThread("endThread");
            endThread.start();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("向线程发送中断请求!");
            endThread.interrupt();
        }
    
    
    }
    
    
    image.png
    public class EndRunnable {
    
        private static class UseRunable implements Runnable {
    
            @Override
            public void run() {
    
                String threadName = Thread.currentThread().getName();
                while (!Thread.currentThread().isInterrupted()) {
    //                当没有向线程发送中断请求,这执行循环里面的值
                    System.out.println(threadName + " is running in while !   interrupt flag is " + Thread.currentThread().isInterrupted());
                }
    
    //            当发送了中断请求,并且中断标识改变了,则退出循环
                System.out.println(threadName + " is run out while !   interrupt flag is " + Thread.currentThread().isInterrupted());
                
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException {
    
            UseRunable useRunable = new UseRunable();
            Thread thread = new Thread(useRunable, "endRunnable");
            thread.start();
            Thread.sleep(20);
            System.out.println("发起中断请求!");
            thread.interrupt(); // 发起中断信号
        }
    }
    
    
    image.png

    相关文章

      网友评论

          本文标题:线程基础,线程之间的共享和协作

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