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;
    }

  

posted @ 2018-02-12 09:57  想54256  阅读(369)  评论(0编辑  收藏  举报