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的和