0301 多线程

创建多线程,除了继承Thread类之外,还可以实现Runnable接口

是因为在继承Thread类的时候 我们创建Thread类对象时,既创建线程对象,又开启线程,这样就会导致耦合性太高。在实现Runnable接口时,这个接口的子类对象就只负责开启线程,让Thread类对象只负责创建线程对象,就实现了分工,就降低了耦合性。

代码展示,首先创建一个类实现这个Runnable接口

public class MyRunnable implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<100;i++){
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
	
}

  代码展示,创建测试

	public static void main(String[] args) {
		//创建线程任务对象
		MyRunnable my=new MyRunnable();
		//创建线程对象
		Thread t=new Thread(my);
		Thread t2=new Thread(my);
		//开启
		t.start();
		t2.start();
	}

  Thread构造方法将线程传进去。

这样就构成了Thread只负责创建线程对象,Runnable只负责创建线程

避免了继承Thread类的单继承的局限性

那我们为了实现多线程,去专门创建一个类,是不是有点浪费

那我们可以使用匿名内部类去实现多线程的操作

代码展示

	public static void main(String[] args) {
		//继承Thread类的方式
		new Thread(){
			public void run() {
				for(int i=0;i<100;i++){
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}.start();
		//实现runnable
		Runnable r=new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=0;i<100;i++){
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		};
		//创建线程对象开启线程
		new Thread(r).start();
	}

  上述代码中分别写了Thread类的匿名内部类的创建线程的方式和runnable匿名内部类的创建线程的方式

线程池

创建线程池可以指定创建几条线程,当开启线程的时候会自动给线程池中空闲的线程去执行

使用线程池的方式

(1)runnable接口

Executors类中有一个public static ExecutorService newFixedThreadPool(int nThreads) 方法,返回一个线程池对象

ExecutorService 线程池类中有一个 submit方法获取某一个线程对象

ExecutorService 线程池类中有一个shutdown方法 关闭线程池

代码展示

我们用runnable接口来实现

首先创建一个runnable子类继承这个runnable接口

public class MyRunnable implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<100;i++){
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
	}
	
}

  测试

	public static void main(String[] args) {
		//获取线程池对象
		ExecutorService  es=Executors.newFixedThreadPool(2);
		//描述线程任务
		MyRunnable r=new MyRunnable();
		//将线程任务对象交给线程池执行
		es.submit(r);
		es.submit(r);
		es.submit(r);
		//销毁线程池
		es.shutdown();
	}

  上述代码中 线程池中只有两条线程,但是我们现编提交给线程池三条任务,那就会先执行完前两条线程任务之后再执行最后一条线程

(2)callable接口

该接口可以返回线程任务结束以后所产生的结果,该接口有一个泛型,就是该线程返回值是什么类型 这个泛型就写什么类型

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

get() 获取Future对象中封装的数据结果

代码展示,与上述步骤一样,只不过就是多了一个返回值

public class MyCallable implements Callable<String>{

	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		return "abc";
	}

	
}

  创建测试

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//获得线程池对象
		ExecutorService es=Executors.newFixedThreadPool(2);
		//创建线程任务
		MyCallable c=new MyCallable();
		//将线程任务交给线程池执行
		Future<String> f=es.submit(c);
		//获取返回值
		String str=f.get();
		System.out.println(str);
		//销毁线程池
		es.shutdown();
	}

 

例举,用线程求1-n的和

创建一个类实现Callable接口

public class GetSum implements Callable<Integer>{

	private int number;
	
	public GetSum(int number) {
		super();
		this.number = number;
	}

	public GetSum() {
		super();
	}

	public Integer call() throws Exception {
		int sum=0;
		for(int i=0;i<=number;i++){
			sum=sum+i;
		}
		return sum;
	}

	
}

  创建测试类

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//获取线程池对象
		ExecutorService es=Executors.newFixedThreadPool(2);
		//创建线程任务
		GetSum g=new GetSum(100);
		GetSum gs=new GetSum(200);
		
		//执行
		Future<Integer> f1=es.submit(g);
		Future<Integer> f2=es.submit(gs);
		System.out.println(f1.get());
		System.out.println(f2.get());
		//关闭
		es.shutdown();
	}

  这样就同时出了1-100的和  and 1-200的和

posted @ 2021-03-01 15:48  公雪  阅读(116)  评论(0编辑  收藏  举报