关于Thread和Runnable的一些笔记
package hello.test; //关于Thread和Runnable的一些 public class test { // 有两种创建线程的方法,一种是将类声明为线程的子类。这个子类应该重写类线程的run方法。然后可以分配和启动子类的实例。 class PrimeThread extends Thread { //可以传一些需要用到的参数进来 long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { //具体是想用这个线程干什么 } } // 创建一个线程并启动它运行 public void test(){ PrimeThread p = new PrimeThread(143); p.start(); } // 创建线程的另一种方法是声明实现可运行接口的类。然后,该类实现了run方法。然后可以分配类的实例,在创建线程时作为参数传递,然后启动。 static class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { for(int i = 0;i<minPrime;i++){ System.out.println(i); } } } // 创建一个线程并启动它运行 public static void test1(){ PrimeRun p1 = new PrimeRun(10); new Thread(p1).start(); } // 每个线程都有一个用于标识的名称。多个线程可以具有相同的名称。如果在创建线程时未指定名称,则会为其生成新名称。除非另有说明,否则将空参数传递给此类中的构造函数或方法将导致引发NullPointerException。 //可以循环写一个多线程的方法 public static void main(String[] args) { try { for( int i = 0;i<4;i++){ test1(); } } catch (Exception e) { System.out.println(e); } } }
上面是一个简单的多线程方法,每个线程可单独执行自己的run方法。
两种方法有自己的优缺点:
源码中的区别
继承Thread类方式:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法(Java虚拟机自动完成)
实现Runnable方式:构造函数中传入了Runnable的引用,传给了Thread类中的成员变量,start()调用了run()方法时的内部判断成员变量Runnable的引用是否为空,若不为空,编译时看的是Runnable的run(),运行时执行的是具体实现类中的run()
优缺点:
继承Thread类方式
好处:可以直接使用Thread类中的方法,代码简单
弊端:同样也是面向对象中的继承的缺点:如果该具体类已经有了其他的父类,那么就不能多重继承Thread类,就不能使用这种方法。此时面向接口编程的优势脱颖而出。
实现Runnable接口方式
好处:即继承的弊端:即使自己定义的线程类有了其他父类也可以实现该Runnable接口。Java中的接口是多实现的,继承是单继承,比较有局限性。
弊端:不能直接使用Thread类中的方法,需要先把Runnable具体实现类对象传递给Thread类并获取到线程对象后,才能得到Thread类的方法,代码相对复杂
还有一种是Callable实现多线程 这种如果方法需要返回值的话调用,提交给ExecutorService返回值是异步执行的,并且可以抛出异常
public static void main(String[] args) throws InterruptedException, ExecutionException { //创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2) ; //此处需要实例化一个本类的对象 因为 在这里,MyCallable是test的内部类,类似于普通的实例变量,如类的静态方法不可以直接调用类的实例变量。在这里,内部类不是静态的内部类,所以,直接赋值(即实例化内部类),所以程序报错。 test test = new test(); //提交任务 Future<Integer> f1 = pool.submit(test.new MyCallable()) ; Future<Integer> f2 = pool.submit(test.new MyCallable()) ; Integer i = f1.get(); Integer i1 = f2.get(); System.out.println(i1); //关闭线程池 pool.shutdown(); } class MyCallable implements Callable<Integer> { public MyCallable() { } @Override public Integer call() throws Exception { int i = 0; for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); i++; } return i; } }