zoukankan      html  css  js  c++  java
  • 线程

    多线程:

      进程:

        进程指正在运行的程序,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。

      线程:

        线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

      总结:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

          单线程:

              一个进程只有一个线程。

          多线程:

              一个进程有多个线程。

      程序运行原理解析:

           分时调度

          所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

                          抢占式调度

             优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

           

          线程在内存里的体现,有几条线程,有几个栈(在java里)

          主线程就是主方法。

    Thread类:

        

         

         

         创建线程的步骤:

            第一种方式:

              1 定义一个类继承Thread。

              2 重写run方法。

              3 创建子类对象,就是创建线程对象。

              4 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。

         代码体现:

               

    public class MyThread extends Thread{
    //重写run方法描述线程任务(先定义一个类继承Thread类)
    public void run() {
        //int y=1/0;
        //Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
    }
    public class Demo02 {
    
        public static void main(String[] args) {
            
            //线程在内存里的体现,有几条线程,有几个栈(在java里)
            //创建线程对象
            MyThread my=new MyThread();
            //开启线程
            my.start();
            //描述主线程的任务
            //currentThread返回(哪个程序正在执行)的Thread对象,()
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    
    }

          获取线程名称:

                

                总结:线程对象调用run方法不开启线程。仅是对象调用方法。线程对象调用start开启线程,并让jvm调用run方法在开启的线程中执行。

    Runnable接口:

          第二种方式:

              

               

               

               

            创建线程的步骤。

            1、定义类实现Runnable接口。

            2、覆盖接口中的run方法。。

            3、创建Thread类的对象

            4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。

            5、调用Thread类的start方法开启线程。

            代码:

                

    public class MyRunnable implements Runnable{
    //第二种方式创建多线程
        //先实现Runnable接口
        public void run() {
            //描述线程任务
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
        //避免了单继承的缺陷,实现了更多的可能性
        //没有将线程任务与线程对象绑在一起
    }
    public class Demo03 {
    
        public static void main(String[] args) {
            // 创建线程任务对象
            MyRunnable my = new MyRunnable();
            // 创建线程对象,并将线程任务交给线程对象
            Thread t = new Thread(my);
            // 开始线程,
            t.start();
            // 描述主线程任务
            for (int i = 0; i < 100; i++) {
                // 先获得当前任务对象,调用方法获得主线程的名字
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    
    }

           好处:

              第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

    匿名内部类的使用:

       使用匿名内部类的方式实现Thread类。     

    public class Demo04 {
    public static void main(String[] args) {
        //匿名内部类
            //new  父类/接口(){}
            //方法重写
            //1:继承Thread类的方式
            Thread t=new Thread(){
                public void run() {
                    for(int i=0;i<100;i++){
                        System.out.println(Thread.currentThread().getName()+":"+i);
                    }
                }
                
            };
            //开启线程
            t.start();
    }
        
    }

        使用匿名内部类的方式实现Runnable接口。

    public class Lianxi01 {
    
        public static void main(String[] args) {
        //创建线程任务对象
            //创建匿名内部类对象
            Runnable r=new Runnable(){
                
                public void run() {
                    //重写run方法
                    for(int i=0;i<100;i++){
                        //获取线程名
                        System.out.println(Thread.currentThread().getName()+":"+i);
                    }
                }
            };
            //创建线程对象,并将线程任务交给线程对象
            Thread t=new Thread(r);
            //开始线程
            t.start();
            //描述主线程任务
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    
    }

     线程池:

        概念:线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

        在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。

    线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

        原理:

          

      可以将线程对象存到ArrayList集合中,泛型是<Thread>,通过add方法存到集合中,再通过remove方法取出来,在用add方法加进去。

    使用线程池方式1:

        Runnable接口:

              Executors:线程池创建工厂类。public static ExecutorService newFixedThreadPool(int   nThreads):返回线程池对象,int 表示的几条线程。

              ExecutorService:线程池类  Future<泛型>    submit(Runnable task):获取线程池的某一个对象,并执行。

              Future接口:用来记录线程任务执行完毕后产生的结果。

       使用线程池中线程对象的步骤:

                   创建线程池对象

                                                       创建Runnable接口子类对象

                                                       提交Runnable接口子类对象

                                                       关闭线程池

       代码:

    public class MyRunnable implements Runnable{
    //第二种方式创建多线程
        //先实现Runnable接口
        public void run() {
            //描述线程任务
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
        //避免了单继承的缺陷,实现了更多的可能性
        //没有将线程任务与线程对象绑在一起
    }
    public class Demo01 {
    
        public static void main(String[] args) {
            //1:获取线程池对象
            ExecutorService es=Executors.newFixedThreadPool(2);
            //创建线程任务对象
            MyRunnable r=new MyRunnable();
            //由线程池随机选一条空闲线程取执行线程任务
            es.submit(r);
            es.submit(r);
            es.submit(r);
            //销毁线程池(不推荐使用)
            es.shutdown();
        }
    
    }

    第二种方式:

        Callable接口:

           Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。

                          ExecutorService:线程池类

                          <T> Future<T> submit(Callable<T> task):获取线程池中的某一个线程对象,并执行线程中的call()方法

          Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

            使用线程池中线程对象的步骤:

            创建线程池对象

            创建Callable接口子类对象

            提交Callable接口子类对象

            关闭线程池

        代码:

          

    public class MyCallable implements Callable<String>{
    
    public String call() throws Exception {
        
        return "abc";
    }
    
    }
    public class Demo02 {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            //获取线程池对象,
            ExecutorService es=Executors.newFixedThreadPool(5);
            //创建线程任务
            MyCallable r=new MyCallable();
            //提交线程任务
            Future<String> f=es.submit(r);
            //获取返回值
            String s=f.get();
            System.out.println(s);
            //关闭线程池
            es.shutdown();
        }
    
    }

    线程练习:

        

    public class GetSum implements Callable<Integer>{
    private int n;
    public GetSum(){
        
    }
    public GetSum(int n){
        this.n=n;
    }
    public Integer call() throws Exception {
        int sum=0;
        for(int i=1;i<=n;i++){
            sum+=i;
        }
        return sum;
    }
    }
    public class Demo03 {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            //分别用两条线程计算1——n的和,一条计算1-100的和,一条计算1-200的和
            //获取线程池对象
            ExecutorService es=Executors.newFixedThreadPool(2);
            //创建线程池任务
            GetSum g1=new GetSum(100);
            GetSum g2=new GetSum(200);
            //提交任务
            Future<Integer> f1=es.submit(g1);
            Future<Integer> f2=es.submit(g2);
            //获取返回值
            Integer sum1=f1.get();
            Integer sum2=f2.get();
            System.out.println(sum1);
            System.out.println(sum2);
            //销毁线程池
            es.shutdown();
        }
    
    }
  • 相关阅读:
    提示“Resource temporarily unavailable”的原因及解决办法
    TQ2440与西门子S7-200 PLC自由口通信实现过程中问题总结
    SQL与SQL Server
    JavaScript:事件对象Event和冒泡
    JavaScript动画:offset和匀速动画详解(含轮播图的实现)
    JavaScript基础:BOM的常见内置方法和内置对象
    JavaScript实现Tab栏切换
    JavaScript基础:DOM操作详解
    JavaScript语法基础:数组的常用方法详解
    JavaScript语法详解:if语句&for循环&函数
  • 原文地址:https://www.cnblogs.com/maxuefeng/p/13924777.html
Copyright © 2011-2022 走看看