zoukankan      html  css  js  c++  java
  • Java——线程的创建,线程池

    线程

    多线程就是一个程序中有多个线程在同时执行。

    多线程下CPU的工作原理

    实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。

    其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,CPU的使用率更高

    一、创建线程

    方法1:继承Thread类,重写run方法

    public class SubThread extends Thread{
    
        public SubThread(){
            super("x5456");     //通过构造方法修改线程名
        }
        
        public void run() {
            for(int i=0;i<100;i++){
                System.out.println(super.getName()+i);
            }
        }
    }

     调用:

    public static void main(String[] args) {
        //创建刚刚继承Thread类的子类的对象
        SubThread st = new SubThread();
        //通过setName方法,修改线程名
        st.setName("x54256");
        //调用对象的start方法,会自动执行我们重写的run方法
        st.start();
    
    
        for(int i=0;i<100;i++) {
            System.out.println(Thread.currentThread().getName()+i);     //获取当前线程的对象,调用getname()方法
        }
    }
    

    方法2:实现接口Runnable,重写run方法

    public class SubRunnable implements Runnable{
        public void run(){
            for(int i=0;i<100;i++){
                try {
                    // 调用Thread类的sleep方法,休眠50ms,由于父接口没有throws异常,so我们只能用try...catch
                    Thread.sleep(50);  
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"..."+i);
            }
        }
    }
    

    调用:

    public static void main(String[] args) {
        //创建实现Runnable接口的类的对象
        SubRunnable sr = new SubRunnable();
        //创建Thread类的对象
        Thread t = new Thread(sr);
        //启动线程
        t.start();
    
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }
    }
    

    方法3:使用匿名内部类,实现多线程程序

    匿名内部类的前提:继承或者接口实现

    使用方法:

    new 父类或者接口(){
      重写抽象方法
    }

    public static void main(String[] args) {
    	//继承方式  XXX extends Thread{ public void run(){}}
    	new Thread(){
    		public void run(){
    			System.out.println("!!!");
    		}
    	}.start();
    	
    	//实现接口方式  XXX implements Runnable{ public void run(){}}
    	
    	Runnable r = new Runnable(){
    		public void run(){
    			System.out.println("###");
    		}
    	};
    	new Thread(r).start();
    	
    	//==================或=====================
    	new Thread(new Runnable(){
    		public void run(){
    			System.out.println("@@@");
    		}
    	}).start();
    	
    } 

    实现接口的好处:

    高内聚,低耦合:模块内能做的事就自己做,模块间的关系要尽量的小

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

    多线程的内存图解:

    线程的一生: 

    二、线程池

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

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

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

    方法1:使用线程池方式--Runnable接口

    public static void main(String[] args) {
        //调用工厂类的静态方法,创建线程池对象(ExecutorService接口的实现类)
        //返回线程池对象,是返回的接口
        ExecutorService es = Executors.newFixedThreadPool(2);  //池内有2个线程
        //调用接口实现类对象es中的方法submit提交线程任务
        //将Runnable接口实现类对象,传递
        es.submit(new SubRunnable());
        es.submit(new SubRunnable());
        es.submit(new SubRunnable());
        es.submit(new SubRunnable());
    }
    

    实现的Runnable接口

    public class ThreadPoolRunnable implements Runnable {
    	public void run(){
    		System.out.println(Thread.currentThread().getName()+" 线程提交任务");
    	}
    }

    方法2:使用线程池方式Callable接口

    之前的实现方法,线程运行完没有返回值,而且不能抛异常。

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

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        //提交线程任务的方法submit方法返回 Future接口的实现类
        Future<Integer> f = es.submit(new SubCallable());
        //获取返回值
        Integer i = f.get();
        System.out.println(i);
    }

    实现的Callable接口

    public class SubCallable implements Callable<Integer>{
        @Override
        public Integer call() {
            return 123;
        }
    }
    

    使用线程实现异步计算

    private int a;
    //通过构造方法传参
    public GetSumCallable(int a){
    	this.a=a;
    }
    
    public Integer call(){
    	int sum = 0 ;
    	for(int i = 1 ; i <=a ; i++){
    		sum = sum + i ;
    	}
    	return sum;
    }
    

    ThreadPoolDemo.java

    /*
     * 使用多线程技术,求和
     * 两个线程,1个线程计算1+100,另一个线程计算1+200的和
     * 多线程的异步计算
     */
    public class ThreadPoolDemo {
    	public static void main(String[] args)throws Exception {
    		ExecutorService es = Executors.newFixedThreadPool(2);
    		Future<Integer> f1 =es.submit(new GetSumCallable(100));
    		Future<Integer> f2 =es.submit(new GetSumCallable(200));
    		System.out.println(f1.get());
    		System.out.println(f2.get());
    		es.shutdown();
    	}
    }
    

    FutureTask的使用

    FutureTask继承了Callable和Future接口,所以它既能像callable一样被Thread执行,也能像Future那样获取结果。

        @Override
        public boolean testServiceUrl(ServiceUrlTestDTO url){
            // 调用地图服务
            Callable<Boolean> callable = new WebServiceUtil(url.getUrl(),url.getProxy(),url.getToken());
            FutureTask<Boolean> futureTask = new FutureTask<>(callable);
            Thread thread = new Thread(futureTask);
            thread.start();
            try {
                Boolean isOK = futureTask.get();
                System.out.println("服务【"+ url.getUrl() +"】测试:"+ isOK);
                return isOK;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return false;
        }
    

      

  • 相关阅读:
    入门菜鸟
    FZU 1202
    XMU 1246
    Codeforces 294E Shaass the Great 树形dp
    Codeforces 773D Perishable Roads 最短路 (看题解)
    Codeforces 814E An unavoidable detour for home dp
    Codeforces 567E President and Roads 最短路 + tarjan求桥
    Codeforces 567F Mausoleum dp
    Codeforces 908G New Year and Original Order 数位dp
    Codeforces 813D Two Melodies dp
  • 原文地址:https://www.cnblogs.com/x54256/p/8443794.html
Copyright © 2011-2022 走看看