zoukankan      html  css  js  c++  java
  • 2016/11/07 线程的创建和启动

    • 继承Thread类创建线程类

    步骤:

    1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务。因此把run()方法称为线程执行体。
    2. 创建Thread子类的实例,即创建了线程对象。
    3. 调用线程对象的start()方法来启动该线程。

    1 public class FirstThread extends Thread { 2 private int i ; 3 public void run() 4 { 5 for(;i < 100 ;i++) 6 { 7 System.out.println(getName() + " " + i); 8 } 9 } 10 public static void main(String[] args) { 11 for(int i = 0 ; i < 100; i++) 12 { 13 System.out.println(Thread.currentThread().getName() + " " + i); 14 if(i == 20) 15 { 16 System.out.println("--------线程1开始--------"); 17 new FirstThread().start(); 18 System.out.println("--------线程2开始--------"); 19 new FirstThread().start(); 20 } 21 } 22 } 23 24 }

    image

        进行多线程编程时不要忘了Java程序运行时默认的主线程,main()方法的方法体就是主线程的线程执行体。

        i变量是FirstThread的实例属性,而不是局部变量,但因为程序每次创建线程对象时都需要创建一个FirstThread对象,所有Thread-0和Thread-1不能共享该实例属性。

        使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量。

    • 实现Runnable接口创建线程类

    步骤:

    1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()的方法体同样是该线程的线程执行体。
    2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。代码如下所示:

    1 SecondThread st = new SecondThread(); 2 new Thread(st).start();

    也可以在创建Thread对象时为该Thread对象指定一个名字,代码如下所示:

    1 SecondThread st = new SecondThread(); 2 new Thread(st,"新线程1").start();

    image

    1 2 public class SecondThread implements Runnable { 3 private int i; 4 @Override 5 public void run() { 6 // TODO Auto-generated method stub 7 for(;i < 100 ;i++) 8 { 9 System.out.println(Thread.currentThread().getName() + " " + i); 10 } 11 12 } 13 14 /** 15 * @param args 16 */ 17 public static void main(String[] args) { 18 // TODO Auto-generated method stub 19 for(int i = 0 ; i < 100 ;i++) 20 { 21 System.out.println(Thread.currentThread().getName() + " " + i ); 22 if(i == 20) 23 { 24 SecondThread st = new SecondThread(); 25 new Thread(st,"新线程1").start(); 26 new Thread(st,"新线程2").start(); 27 } 28 } 29 30 } 31 32 } 33 34

            上面程序中的代码创建了两个Thread对象,并调用start()方法来启动这两个线程。在FirstThread和SecondThread中创建线程对象的方式有所区别:前者直接创建的Thread子类即可代表线程对象;后者创建的Runnable对象只能作为线程对象的target。

            两个子线程的i变量是连续的,也就是采用Runnable接口的方式创建的多个线程可以共享线程类的实例属性。这是因为在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程可以共享一个target,所以多个线程可以共享一个线程类(实际上应该是线程的target类)的实例属性。

    • 使用Callable和Future创建线程

        从Java 5 开始,Java提供了Callable接口,该接口怎么看都像是Runnable接口的增强版,Callable接口提供了一个call()方法。问题是:Callable接口是Java 5新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。而且call()方法还有一个返回值——

    call()方法并不是直接调用,它是作为线程执行体被调用的。

    image

    步骤:

    1. 创建Callable接口实现类,并实现call()方法,该call(0方法有返回值。
    2. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
    3. 使用FutureTask对象作为Thread对象的target创建并启动新线程。
    4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

    1 import java.util.concurrent.Callable; 2 import java.util.concurrent.ExecutionException; 3 import java.util.concurrent.FutureTask; 4 5 6 public class ThirdThread implements Callable<Integer> { 7 8 @Override 9 public Integer call() throws Exception { 10 // TODO Auto-generated method stub 11 int i = 0; 12 for(; i < 100 ; i++ ) 13 { 14 System.out.println(Thread.currentThread().getName() + "的循环变量i的值:" + i); 15 } 16 return i; 17 } 18 19 /** 20 * @param args 21 */ 22 public static void main(String[] args) { 23 // TODO Auto-generated method stub 24 ThirdThread rt = new ThirdThread(); 25 FutureTask<Integer> task = new FutureTask<Integer>(rt); 26 for(int i = 0 ;i < 100 ;i++) 27 { 28 System.out.println(Thread.currentThread().getName()+ "的循环变量i的值:" + i); 29 if(i == 20) 30 { 31 new Thread(task,"有返回值的线程").start(); 32 } 33 } 34 try { 35 System.out.println("子线程的返回值:" + task.get()); 36 } catch (InterruptedException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } catch (ExecutionException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } 43 44 45 } 46 47 } 48

    上面程序中创建Callable()实现类与创建Runable实现类并没有太大的差别,只是Callable的call()方法允许声明抛出异常,而且允许带返回值。

    程序先创建一个Callable实现类的实例,然后将该实例包装成一个FutureTask对象。

  • 相关阅读:
    手写web框架之加载配置项目
    JAVA中注解的实现原理
    使用Mock 测试 controller层
    如何写resultful接口
    RSA加密、解密、签名、验签的原理及方法
    AES256位加密
    聊聊分布式事务,再说说解决方案
    分布式锁简单入门以及三种实现方式介绍
    redis总结(面试中容易遇到的)
    字符串匹配的KMP算法
  • 原文地址:https://www.cnblogs.com/zcr3108346262/p/6039393.html
Copyright © 2011-2022 走看看