精华内容
下载资源
问答
  • 主要介绍了Java创建子线程的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • java创建子线程为什么要有两种方法---马克-to-win java视频
  • java创建子线程为什么要有两种方法4---马克-to-win java视频
  • java创建子线程为什么要有两种方法3---马克-to-win java视频
  • java创建子线程为什么要有两种方法2---马克-to-win java视频
  • Java创建子线程的两条不归路

    千次阅读 2020-05-20 16:03:19
    Java创建子线程的两条不归路 摘要:    其实两种方法归结起来看还是一种,都是利用Thread的构造器进行创建,区别就是一种是无参的,一种是有参的。 一、继承Thread线程类:   通过继承Thread类,重写run方法,...

    Java创建子线程的两条不归路

    摘要:
       其实两种方法归结起来看还是一种,都是利用Thread的构造器进行创建,区别就是一种是无参的,一种是有参的。

    一、继承Thread线程类:
      通过继承Thread类,重写run方法,子类对象就可以调用start方法启动线程,JVM就会调用此线程的run方法。
    代码如下:

     class MyThread extends Thread {
        public MyThread() { 
            super(); 
        }
            @Override
            public void run() { 
            	// 线程执行结束
                System.out.println("执行完成! " + getName());
      	 }
            
    }
    
    public class HelloWorld {
    public static void main(String[] args) {
        // 创建线程t1
        Thread t1 = new MyThread(); 
        // 开始线程t1
        t1.start();
    }
    }
    

    注意: 如果直接调用run方法,程序只会按照顺序执行主线程这一个线程。不会创建一个线程。

    public class HelloWorld {
    public static void main(String[] args) {
        // 创建线程t1
        Thread t1 = new MyThread();// 开始线程t1
        t1.run();
    }
    }
    


    二、实现Runnable接口:
       因为Thread类实现了Runnable接口,我们可以直接实现Runnable,然后通过Thread(Runnable target)来创建线程。

    //线程执行对象
    public class Runner implements Runnable { 
            // 编写执行线程代码
            @Override
            public void run() { 
            }
            // 线程执行结束
            System.out.println("执行完成! " + Thread.currentThread().getName());
        }
    }
    
    
    public class HelloWorld {
        public static void main(String[] args) {
            // 创建线程t1,参数是一个线程执行对象Runner
            Thread t1 = new Thread(new Runner()); 
            // 开始线程t1
            t1.start(); 
        }
    }
    

    注意: (1)实现Runnable接口,就不能调用Thread类的方法了,但是可以通过Thread.currentThread()进行调用。
    (2)可能有的人很好奇,thread.start();为什么调用我们实现Runnable类的run方法,而不是Thread类的run方法。这就要从源码分析了:

    //Thread的run方法,调用target.run()
    public void run() {
            if (target != null) {
                target.run();
            }
     }
     //Thread的构造器
    public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    

    Thread类的构造器会调用init方法,会把我们传过去的Runnable对象赋值给Thread类的target,所以target.run()就是我们实现Runnable类,调用重写的run方法。

    private Runnable target;
    


    二、比较创建线程的两种方法:

    开发中:优先选择,实现Runnable接口的方式

    原因:(1)实现的方式没有类的单继承的局限性

       (2)实现的方式更适合来处理多个线程共享数据的情况。

    联系: Thread实现了Runnable

    相同点: 两者都需要重写run()。


    总结:两种方法各有好坏,所谓萝卜青菜各有所爱,除了自身喜好,别忘了实际的应用场景。(◔◡◔)


    哪里写得不好或者想讨论的小伙伴欢迎留言哦!
    展开全文
  • Java多线程(二、创建子线程

    千次阅读 2018-06-05 19:08:10
    今天来讲讲Java如何创建一个线程。大多数情况下,通过实例化一个Thread对象来创建一个线程Java定义了两种方式:实现Runnable接口继承Thread类实现Runnable接口创建线程的最简单的方法就是创建一个Runnable口的类。...

    今天来讲讲Java如何创建一个线程。

    大多数情况下,通过实例化一个Thread对象来创建一个线程,Java定义了两种方式:

    • 实现Runnable接口
    • 继承Thread类

    实现Runnable接口

    创建线程的最简单的方法就是创建一个Runnable口的类。Runnable抽象了一个执行代码单元。为实现Runnable接口,一个类仅需实现一个run()的简单方法,在run()方法中可以定义代码来构建新的线程。创建一个线程必须理解下面这段话:

    run()方法能够让主线程那样调用其他方法,引用其他类,声明变量。仅有的不同的是run()方法在程序中确立另一个并发的线程执行入口。当run()方法运行完毕时,该线程结束。

    在你已经创建了实现Runnable接口的类以后,你要在类内部实例化一个Thread类的对象。

    Thread(Runnable threadOb,String threadName)

    该构造函数中,threadOb时一个实现Runnable接口的实现类,threadName参数则是你新建线程的线程名称,这定义了线程执行的起点。

    建立了新的线程,它并不能运行,需要调用start方法来执行线程的run()方法。本质上,start()方法执行的是一个对run()的调用。

    public class Test1 {
    
        public static void main(String[] args) throws InterruptedException {
            new XkThread();
            try {
                for(int i=1;i<=5;i++){
                    Thread.currentThread().sleep(1000);//让当前线程睡眠1秒    
                    System.out.println("大家好,我是主线程:"+i);
                }
                //需要捕获sleep()方法可能抛出的异常
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class XkThread implements Runnable {
        private Thread th;
    
        public XkThread() {
            th=new Thread(this);
            System.out.println("开始调用run()方法");
            th.start();//调用run()方法
        }
        @Override
        public void run() {
            try {
                for(int i=1;i<=5;i++){
                    th.sleep(1000);//让线程睡眠1秒    
                    System.out.println("大家好,我是子线程:"+i);
                }
                //需要捕获sleep()方法可能抛出的异常
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
        }
        
    }
    
    
    

    在NewThread中构造函数中,新的Thread对象由下面语句创建:

    th=new Thread(this);

    通过前面的语句this表明了在this对象中你想要新的线程调用run()方法。然后start()被调用,以run()方法为开始启动了线程的执行。这使子线程for循环开始执行。调用start()方法之后,NewThread的构造函数返回到main()。当主线程被恢复,主线程开始执行自己的for循环。两个线程同时运行,共享CPU,直到它们的循环结束。

    运行结果:

    开始调用run()方法
    大家好,我是主线程:1
    大家好,我是子线程:1
    大家好,我是子线程:2
    大家好,我是主线程:2
    大家好,我是子线程:3
    大家好,我是主线程:3
    //省略
    

    继承Thread类

    创建线程的另一个途径就是继承Thread类,然后创建子类的实例。当一个类继承Thread类时,它必须重写run()方法,这个run()方法时新线程的入口。它也必须调用start()方法来启用新线程执行。

    public class Test2 {
    
    	public static void main(String[] args) {
    		new MyThread("child Thread");
    		System.out.println("开始执行主线程的for循环");
    		try {
    			for(int i=1;i<=5;i++){
    				Thread.currentThread().sleep(1000);//让主线程睡眠1秒	
    				System.out.println("大家好,我是主线程:"+i);
    			}
    			//需要捕获sleep()方法可能抛出的异常
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    class MyThread extends Thread{
    
    	public MyThread(String threadName) {
    		super(threadName);
    		System.out.println("开始调用start()方法");
    		start();
    	}
    	
    	@Override
    	public void run() {
    		System.out.println("开始执行子线程的for循环");
    		try {
    			for(int i=1;i<=5;i++){
    				sleep(500);//让子线程睡眠0.5秒	
    				System.out.println("大家好,我是子线程:"+i);
    			}
    			//需要捕获sleep()方法可能抛出的异常
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    	
    }

    创建一个子线程MtThread,在构造函数中调用start()方法启动子线程,然后主线程也继续运行,为了让主线程最后结束,在这里我让子线程睡眠时间为0.5秒,主线程睡眠时间为1秒,这样子总可以让主线程最后结束。

    运行结果:

    开始调用start()方法
    开始执行主线程的for循环
    开始执行子线程的for循环
    大家好,我是子线程:1
    大家好,我是子线程:2
    大家好,我是主线程:1
    大家好,我是子线程:3
    大家好,我是主线程:2
    大家好,我是子线程:4
    大家好,我是子线程:5
    大家好,我是主线程:3
    大家好,我是主线程:4
    大家好,我是主线程:5
    

    最后

    到这里,你一定很奇怪为什么Java有两种创建子线程的方法呢?哪一种更好呢?所有的问题都归于一点,Thread类定义了多种方法可以被子类重载。对于所有的方法,唯一的必须重写的是run()方法。而实现Runnable接口也只需要重写run()方法。因此,如果你不重载Thread的其他方法,最好是实现Runnable接口。当然了,这得看个人习惯。


    展开全文
  • java创建子线程为什么要有两种方法?马克-to-win:通过以下两种方法创建子线程:1)声明一个Thread类的子类。 2)实现runnable接口。java的官方文档也没强调这二者有什么区别。马克-to-win:笔者认为,既然java只允许...

    java创建子线程为什么要有两种方法?  
    马克-to-win:通过以下两种方法创建子线程:1)声明一个Thread类的子类。 2)实现runnable接口。java的官方文档也没强调这二者有什么区别。马克-to-win:笔者认为,既然java只允许继承一个类,如果你这个类本身就是某个类的子类,那你要想创建子线程,你就只能实现runnable这个接口。

    例:1.3.2
    class ThreadMark_to_win extends Thread {
        public void run() {
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程i = " + i);
            }
        }
    }
    public class Test {
        public static void main(String[] args)  {
            Thread t = new ThreadMark_to_win();
            t.start();
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("主线程i = " + i);
            }
        }
    }

    更多请见:https://blog.csdn.net/qq_44639795/article/details/103106035

    展开全文
  • Java创建线程的8种方式

    万次阅读 多人点赞 2018-07-21 21:16:51
    Java创建启动线程的多种方式 1、继承Thread类,重写run()方法 2、实现Runnable接口,重写run() 3、匿名内部类的方式 4、带返回值的线程(实现implements Callable&lt;返回值类型&gt;)————以上3...

     

    //方式1
    package cn.itcats.thread.Test1;
    
    public class Demo1 extends Thread{
    	
        //重写的是父类Thread的run()
    	public void run() {
    		System.out.println(getName()+"is running...");
    	}
    	
    	
    	public static void main(String[] args) {
    		Demo1 demo1 = new Demo1();
    		Demo1 demo2 = new Demo1();
    		demo1.start();
    		demo2.start();
    	}
    }
    
    • 2、实现Runnable接口,重写run()

    实现Runnable接口只是完成了线程任务的编写
    若要启动线程,需要new Thread(Runnable target),再有thread对象调用start()方法启动线程
    此处我们只是重写了Runnable接口的Run()方法,并未重写Thread类的run(),让我们看看Thread类run()的实现
    本质上也是调用了我们传进去的Runnale target对象的run()方法

    //Thread类源码中的run()方法
    //target为Thread 成员变量中的 private Runnable target;
    
     @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }

    所以第二种创建线程的实现代码如下:

    package cn.itcats.thread.Test1;
    
    /**
     * 第二种创建启动线程的方式
     * 实现Runnale接口
     * @author fatah
     */
    public class Demo2 implements Runnable{
    
        //重写的是Runnable接口的run()
    	public void run() {
    			System.out.println("implements Runnable is running");
    	}
    	
    	public static void main(String[] args) {
    		Thread thread1 = new Thread(new Demo2());
    		Thread thread2 = new Thread(new Demo2());
    		thread1.start();
    		thread2.start();
    	}
    
    }
    

    实现Runnable接口相比第一种继承Thread类的方式,使用了面向接口,将任务与线程进行分离,有利于解耦

    • 3、匿名内部类的方式

    适用于创建启动线程次数较少的环境,书写更加简便
    具体代码实现:

    package cn.itcats.thread.Test1;
    /**
     * 创建启动线程的第三种方式————匿名内部类
     * @author fatah
     */
    public class Demo3 {
    	public static void main(String[] args) {
    		//方式1:相当于继承了Thread类,作为子类重写run()实现
    		new Thread() {
    			public void run() {
    				System.out.println("匿名内部类创建线程方式1...");
    			};
    		}.start();
    		
    		
    		
    		//方式2:实现Runnable,Runnable作为匿名内部类
    		new Thread(new Runnable() {
    			public void run() {
    				System.out.println("匿名内部类创建线程方式2...");
    			}
    		} ).start();
    	}
    }
    
    • 4、带返回值的线程(实现implements  Callable<返回值类型>)

    以上两种方式,都没有返回值且都无法抛出异常。
    Callable和Runnbale一样代表着任务,只是Callable接口中不是run(),而是call()方法,但两者相似,即都表示执行任务,call()方法的返回值类型即为Callable接口的泛型
    具体代码实现:

    package cn.itcats.thread.Test1;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.RunnableFuture;
    
    /**
     * 方式4:实现Callable<T> 接口
     * 含返回值且可抛出异常的线程创建启动方式
     * @author fatah
     */
    public class Demo5 implements Callable<String>{
    
    	public String call() throws Exception {
    		System.out.println("正在执行新建线程任务");
    		Thread.sleep(2000);
    		return "新建线程睡了2s后返回执行结果";
    	}
    
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		Demo5 d = new Demo5();
    		/*	call()只是线程任务,对线程任务进行封装
    			class FutureTask<V> implements RunnableFuture<V>
    			interface RunnableFuture<V> extends Runnable, Future<V>
    		*/
    		FutureTask<String> task = new FutureTask<>(d);
    		Thread t = new Thread(task);
    		t.start();
    		System.out.println("提前完成任务...");
    		//获取任务执行后返回的结果
    		String result = task.get();
    		System.out.println("线程执行结果为"+result);
    	}
    	
    }
    
    • 5、定时器(java.util.Timer)

    关于Timmer的几个构造方法


    执行定时器任务使用的是schedule方法:


    具体代码实现:

    package cn.itcats.thread.Test1;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * 方法5:创建启动线程之Timer定时任务
     * @author fatah
     */
    public class Demo6 {
    	public static void main(String[] args) {
    		Timer timer = new Timer();
    		timer.schedule(new TimerTask() {
    			@Override
    			public void run() {
    				System.out.println("定时任务延迟0(即立刻执行),每隔1000ms执行一次");
    			}
    		}, 0, 1000);
    	}
    	
    }
    

    我们发现Timer有不可控的缺点,当任务未执行完毕或我们每次想执行不同任务时候,实现起来比较麻烦。这里推荐一个比较优秀的开源作业调度框架“quartz”,在后期我可能会写一篇关于quartz的博文。

    • 6、线程池的实现(java.util.concurrent.Executor接口)

    降低了创建线程和销毁线程时间开销和资源浪费
    具体代码实现:

    package cn.itcats.thread.Test1;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    
    public class Demo7 {
    	public static void main(String[] args) {
    		//创建带有5个线程的线程池
    		//返回的实际上是ExecutorService,而ExecutorService是Executor的子接口
    		Executor threadPool = Executors.newFixedThreadPool(5);
    		for(int i = 0 ;i < 10 ; i++) {
    			threadPool.execute(new Runnable() {
    				public void run() {
    					System.out.println(Thread.currentThread().getName()+" is running");
    				}
    			});
    		}
    		
    	}
    }
    

    运行结果:
    pool-1-thread-3 is running
    pool-1-thread-1 is running
    pool-1-thread-4 is running
    pool-1-thread-3 is running
    pool-1-thread-5 is running
    pool-1-thread-2 is running
    pool-1-thread-5 is running
    pool-1-thread-3 is running
    pool-1-thread-1 is running
    pool-1-thread-4 is running

    运行完毕,但程序并未停止,原因是线程池并未销毁,若想销毁调用threadPool.shutdown();    注意需要把我上面的
    Executor threadPool = Executors.newFixedThreadPool(10);              改为  
    ExecutorService threadPool = Executors.newFixedThreadPool(10);     否则无shutdown()方法

    若创建的是CachedThreadPool则不需要指定线程数量,线程数量多少取决于线程任务,不够用则创建线程,够用则回收。

    • 7、Lambda表达式的实现(parallelStream)

      package cn.itcats.thread.Test1;
      
      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.List;
      
      /**
       * 使用Lambda表达式并行计算
       * parallelStream
       * @author fatah
       */
      public class Demo8 {
      	public static void main(String[] args) {
      		List<Integer> list = Arrays.asList(1,2,3,4,5,6);
      		Demo8 demo = new Demo8();
      		int result = demo.add(list);
      		System.out.println("计算后的结果为"+result);
      	}
      	
      	public int add(List<Integer> list) {
      		//若Lambda是串行执行,则应顺序打印
      		list.parallelStream().forEach(System.out :: println);
      		//Lambda有stream和parallelSteam(并行)
      		return list.parallelStream().mapToInt(i -> i).sum();
      	}
      }
      

      运行结果:
      4
      1
      3
      5
      6
      2
      计算后的结果为21
      事实证明是并行执行
       

    • 8、Spring实现多线程

    (1)新建Maven工程导入spring相关依赖
    (2)新建一个java配置类(注意需要开启@EnableAsync注解——支持异步任务)

    package cn.itcats.thread;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @Configuration
    @ComponentScan("cn.itcats.thread")
    @EnableAsync
    public class Config {
    	
    }
    

    (3)书写异步执行的方法类(注意方法上需要有@Async——异步方法调用)

    package cn.itcats.thread;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class AsyncService {
    	
    	@Async
    	public void Async_A() {
    		System.out.println("Async_A is running");
    	}
    	
    	@Async
    	public void Async_B() {
    		System.out.println("Async_B is running");
    	}
    }
    

    (4)创建运行类

    package cn.itcats.thread;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Run {
    	public static void main(String[] args) {
    		//构造方法传递Java配置类Config.class
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
    		AsyncService bean = ac.getBean(AsyncService.class);
    		bean.Async_A();
    		bean.Async_B();
    	}
    }
    

     

    展开全文
  • Java线程

    2020-12-21 16:19:13
    通过Thread直接创建子线程 实现Runnable接口创建自线程 线程状态(创建、就绪、执行、阻塞、终止) 线程常用方法 inturrupt打断线程 join()线程并行执行变为串行 理解线程的概念 一个程序至少有一个进程,一个进程...
  • Java之多线程创建

    千次阅读 2019-03-20 19:10:31
    Java线程归纳前言传统的线程创建继承Thread类实现Runnable接口两者的共同点两者差别JDK 1.5开始出现的线程创建 前言 进程是资源分配的最小单位,而线程是执行任务的最小的单位。进程里的线程可以共享该进程拥有的...
  • java创建线程的4种方式

    千次阅读 2019-04-25 16:00:23
    java线程创建方式有几种?这种问题在面试中经常被问到,你可能心里马上反映出两种方式(实现Runnable、继承Thread),当你把这两种叙述给面试官听后,面试官会觉得你该掌握的知识已经有了,但是仅仅而已。如果你还说...
  • 但在多线程的异步开发模式下,数据的传递和返回和同步开发模式有很大的区别。由于线程的运行和结束是不可预料的,因此,在传递和返回数据时就无法象函数一样通过函数参数和return语句来返回数据
  • 4、使用线程池创建(使用java.util.concurrent.Executor接口) 其中第一、二中最为简单,我已经在前面线程部分详细解释过,不懂得可以去看看:多线程。 今天我们聊聊其他两种和他们的区别。 1、使用Callable接口和...
  • java创建线程的四种方式及其区别

    千次阅读 2019-04-26 18:35:25
    java创建线程有如下四种方式: 继承Thread类创建线程 实现Runnable接口创建线程 使用Callable和Future创建线程 使用线程池创建(使用java.util.concurrent.Executor接口) 下面分别介绍这四种创建多线程的方式...
  • Java中如何创建线程

    千次阅读 2019-03-17 07:54:46
    进程和线程的关系 进程是所有线程的集合,每一个线程是进程中的一条执行路径。 什么是进程,什么是线程 进程,每个正在系统上运行的程序都是一个进程。 线程线程是一组指令的集合,或者是程序的特殊段,它可以...
  • 二种方法创建子线程---马克-to-win java视频的详细描述与介绍
  • 创建两个分线程,让其中一个线程输出1-100之间的偶数,另一 个线程输出1-100之间的奇数。 解答 方法1 // 定义子类继承Thread类 class MyThread1 extends Thread{ //子类中重写Thread类中的run方法。 @Override ...
  • java 创建线程的三种方式、创建线程池的四种方式

    万次阅读 多人点赞 2019-02-23 21:01:44
    java创建线程的三种方式: 继承Thread类创建线程类 实现Runnable接口 通过Callable和Future创建线程 java创建线程池的四种方式: newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理...
  • Java创建线程及配合使用Lambda

    万次阅读 2018-08-30 16:32:13
    说明Java创建线程的三种方式,以及在创建线程的时候利用Lambda简化代码的实现
  • java开启子线程的方法及优化

    千次阅读 2018-08-22 14:54:09
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。  下面代码说明: (1). newCachedThreadPool 创建一个可缓存...
  • java创建线程的3种方式

    千次阅读 2018-07-12 17:33:01
    Java 提供了三种创建线程的方法:通过实现 Runnable 接口;通过继承 Thread 类本身;通过 Callable 和 Future 创建线程通过实现 Runnable 接口package com.demo.thread.Runnable; public class RunnableDemo ...
  • Java线程详解(一)Java线程入门

    千次阅读 多人点赞 2019-11-27 20:18:20
    最近听很多面试的小伙伴说,网上往往是一篇一篇的Java线程的文章,除了书籍没有什么学习多线程的一系列文章。但是仅仅凭借一两篇文章很难对多线程有系统的学习,而且面试的时候多线程这方面的知识往往也是考察的...
  • Java线程面试题

    千次阅读 2019-10-30 13:58:47
    在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口),然后逐渐问到并发问题像在Java并发编程的...
  • Java线程创建任务和线程

    千次阅读 2016-12-14 17:19:47
    Runnable创建线程任务就是对象。为了创建任务,必须首先为任务定义一个类。任务类必须实现Runnable接口。Runnable接口非常简单,它只包含一个run方法。需要实现这个方法来告诉系统线程将如何运行。开发一个任务类的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 235,861
精华内容 94,344
关键字:

java创建子线程

java 订阅