Java创建多线程的四种常用方式

提醒:下文内容仅就总结多线程的创建方式,不考虑线程安全问题,且为了直观,在异常处理方面大量省略

一.程序,进程,线程的基本概念


 这里只要做简单的了解即可,红字部分有印象就行,详细内容在虚拟机部分做具体解释

二.创建多线程的四种方式(以多线程抢票为背景)

①在JDK5.0之前:

 方式一:继承Thread类

    //1.创建一个子类继承Threadclass Mythread extends Thread{private static int ticket=100;//2.重写run方法@Overridepublic void run() {while (true){if(ticket>=1){System.out.println(getName()+"抢到票"+ticket);ticket--;}else{System.out.println(getName()+"票已售罄");break;}}}}public class Test1  {public static void main(String[] args) {// 3.实例化子类对象Mythread t1= new Mythread();Mythread t2= new Mythread();t1.setName("线程一");t2.setName("线程二");// 4.start开启线程t1.start();t2.start();}}

总结:继承Thread创建多线程的步骤:
  1.创建一个子类继承Thread
  2.重写run方法
  3.实例化子类对象
  4.start开启线程


 方式二:实现Runnable接口

    //1.创建一个实现Runnable接口的类class Mythread implements Runnable{private int ticket=100;//2.重写run方法@Overridepublic void run() {while (true){if(ticket>=1){System.out.println(Thread.currentThread().getName()+"抢到票"+ticket);ticket--;}else {System.out.println(Thread.currentThread().getName()+"票已售罄");break;}}}   
}public class Test1 {public static void main(String[] args) {//3.创建一个实现类的对象Mythread t= new Mythread();/*4.每个线程各自创建一个以实现类对象为参数的Thread  类的对象*/Thread t1=new Thread(t);Thread t2=new Thread(t);t1.setName("线程一");t2.setName("线程二");//5.start开启进程t1.start();t2.start();}}

总结:继承Thread创建多线程的步骤:
  1.创建一个实现Runnable接口的类
  2.重写run方法
  3.创建一个实现类的对象
  4.每个线程各自创建一个以实现类对象为参数的Thread类的对象
  5.start开启进程


关于Thead带参构造器的源码:

public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);
}

不难发现,其参数必须是Runnable接口实现类的对象

注:相比于继承Thread类,方式二可以直接实现数据共享,方式一需要用static修饰成员变量(这一点在讲同步的时候尤其重要)


②在JDK5.0新增:

 方式三:借助FutureTask类和Callable接口

    //1.创建一个实现Callable接口的类class MyThread implements Callable {//2.重写call函数(由于多态,Obj的返回值类型可以自动向下转化)@Overridepublic Object call() throws Exception {int sum=0;for (int i = 0; i <100 ; i++) {if (i % 2 == 0) {sum += i;System.out.println(i);}}return sum;}}public class Test1 {public static void main(String[] args) throws InterruptedException, UnknownHostException {//3.创建一个实现类的对象MyThread myThread=new MyThread();//4.创建一个FutureTask的对象,传入Callable实现类的对象FutureTask futureTask=new FutureTask(myThread);//5.创建一个Thread类的对象传入对象futureTask并startnew Thread(futureTask).start();//6.如果需要返回值,再调用futureTask.get()来取返回值try {Object sum=futureTask.get();System.out.println("总和为"+sum);} catch (ExecutionException e) {e.printStackTrace();}}}

总结:
  1.创建一个实现Callable接口的类
  2.重写call方法
  3.创建一个实现类的对象
  4.创建一个FutureTask的对象,传入Callable实现类的对象
  5.创建一个Thread类的对象传入对象futureTask并start
  6.如果需要call函数的返回值,需要调用future.get()的方法

注:Callable可以简单认为是Runnable的升级版,Callable允许有返回值功能更强大


关于FutureTask构造器的源码解析


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tidEObNM-1622460716694)( https://i.loli.net/2020/07/20/mShDs6cjOlNERJg.png)]

不难发现,FutrueTask其实继承了Runnable,所以在Tread实例化的时候可以直接带FutureTask的对象,并且上图中的构造器中对callable进行了回调


 方式四:调用线程池来实现多线程(开发中主要还是用线程池)

    //1.创建一个实现Runnable接口的类class Mythread implements Runnable {private int ticket=100;//2.重写run方法@Overridepublic void run() {while (true){if(ticket>=1){System.out.println(Thread.currentThread().getName()+"票"+ticket);ticket--;}else{System.out.println(Thread.currentThread().getName()+"售罄了");break;}}}}public class Test1 {public static void main(String[] args) {//3.提供指定线程数量的线程池ExecutorService service=Executors.newFixedThreadPool(10);//service.submit(new Mythread());//适用于Callable//4.执行指定的线程操作需要提供实现Runnable接口或Callable接口的类service.execute(new Mythread());//适用于Runnableservice.execute(new Mythread());//关闭线程池service.shutdown();}}

线程池的好处:


注:用survice.getClass()可以找到survice的实现类,可以发现是ThreadPoolExxcutor,然后上属的方法要通过强转才能用:
ThreadPoolExxcutor survice1=(ThreadPoolExxcutor) survice;


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部