zoukankan      html  css  js  c++  java
  • java--线程的构建(来源疯狂java讲义)

    首先在这里先介绍一下线程和进程的区别:

    进程是一个程序一次运行的状态,进程是系统进行资源分配和调度的一个独立的单位。

    进程包括三个特征:

    独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己的私有地址空间,在没有经过进程本身允许的情况下,一个用户的进程不可以直接访问其他进程的地址空间。

    动态性:进程和程序的区别在于,程序只是一个静态的指令集合。而进程是一个正在系统中活动的指令集合。在进程中加入了时间概念。进程具有自己的生命周期和各种不同的状态。这些概念在程序中都是不具备的。

    并发性:多个进程可以在单个处理器上并发执行。多个进程之间不会互相影响。

    并发性和并行性:这是两个不同的概念,并行性是指在同一时刻,有多条指令在多个处理器上同时执行,并发是指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

    其次,我们介绍一下线程的创建和启动:

    线程的创建有:继承Thread类、实现Runnable接口、使用CallableFuture创建线程

    1、继承Thread类:

    它在java.lang.Thread   

    原形为:

    Public class Thread extends Object implements Runnable{}

    它实现了Runnable 接口。

    通过继承Thread类创建线程类步骤入下:

    (1)、定义Thread类的子类,并重写run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。

    (2)创建Thread子类的实例,即创建线程对象。

    (3)调用线程对象的start()方法来启动该线程。

    Start()方法,就是提醒一下该线程该运转了,然后立刻读取start()下面的代码。

    下面列举一个通过继承Thread类来创建线程类。

     1 Public class FistThread extends Thread{
     2 
     3 Private int i;
     4 
     5 //重写run 方法,run方法的方法体就是线程的执行体
     6 
     7 Public void run(){
     8 
     9 For ( ; i<100 ; i++){
    10 
    11 //当线程类继承Thread类时,直接使用this即可以获取当前线程
    12 
    13 //Thread对象的getName()返回当先线程的名字
    14 
    15 //因此可以直接调用getName()方法返回当前线程的名字
    16 
    17 System.out.println ( getName() +” ”+i);
    18 
    19 }
    20 
    21 }
    22 
    23 Public static void main (String [] args){
    24 
    25 For(int i=0; i<100 ;i++){
    26 
    27 //调用Thread的currentThread()方法获取当前线程
    28 
    29 System.out.println(Thread.currentThread().getName()+ “ ”+i);
    30 
    31 If(i==20){
    32 
    33 //创建启动第一个线程
    34 
    35 new FirstThread().start();
    36 
    37 //创建启动第二个线程
    38 
    39 new FirstThread().start();
    40 
    41 } 
    42 
    43 }
    44 
    45 }
    46 
    47 }

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

    就上面的例子,相当于创建了两个线程,每个线程都能够运行100次。

    2、实现Runnable 接口创建线程类:

    实现Runnable接口来创建并启动多线程步骤如下:

    (1)、定义Runnable接口的实现类,并重写该类接口的run方法,该run方法的方法体同样是该线程的执行体。

    (2)、创建Runnable实现类的实例,并以此例作为Threadtarget来创建Thread对象,该Thread对象才是真正的线程对象。

    (3)、调用线程对象start()方法来启动该线程。

    下面列举一个通过实现Runnable接口创建线程类。

     1 Public class SecondThread implements Runnable{
     2 
     3 Private int i;
     4 
     5 Public void run (){
     6 
     7 For( ; i<100;i++){
     8 
     9 //当线程类实现Runnable接口时
    10 
    11 //如果想获得当前线程,只能用Thread.currentThread()方法
    12 
    13 System.out.println(Thread.currentThread().getName() +” ”+i);
    14 
    15 }
    16 
    17 }
    18 
    19 Public static void main(String []  args){
    20 
    21 For (int i=0;i<100;i++){
    22 
    23 System.out.println(Thread.currentThread().getName()+” ”+i);
    24 
    25 If(i==20){
    26 
    27 SecondThread st =new SecondThread();
    28 
    29 //通过new Thread(target,name)方法创建新线程
    30 
    31 New Thread (st,”新线程1”).start();
    32 
    33 New Thread(st,”新线程2”).start();
    34 
    35 }
    36 
    37 }
    38 
    39 }
    40 
    41 }

    运行结果可以看出去两个线程i变量是连续的,也就是采用Runnable 接口的方式创建多个线程可以共享线程类的实例属性。

    3、使用Callable 和 Future 创建线程

    首先为什么出现这种方法。先看看前两个方法创建线程的缺点。

    通过实现 Runnable 接口创建多线程时,Thread 类的作用就是把run方法包装成线程执行体,那么是否可以直接把任何方法包装成线程执行体?Java 目前是不行的。

    Java 5 开始,Java 提供了Callable 接口,该接口是Runnable 的增强版,Callable 接口提供了一个call方法,该方法可以有返回值 也可以声明抛出异常。

    注意:Callable 接口有泛型限制,Callable 接口里的泛型参数类型与call方法返回值类型相同。

    创建并启动有返回值得线程的步骤如下:

    (1)、创建Callable 接口的实现类,并实现call()方法,该call方法作为线程执行体,且该call方法有返回值。

    (2)创建Callable实现类的实例,并使用FutureTask类来包装Callable对象,该FutureTask 对象封装了该Callable对象的call方法的返回值。

    (3)使用FutureTask 对象作为Thread 对象的target  来创建并启动线程。

    (4)调用FutureTask 对象的get方法来获得子线程执行结束之后的返回值。

    下面程序通过实现Callable 接口来实现线程类,并启动该线程:

     1 import java.util.concurrent.Callable;
     2 
     3 import java.util.concurrent.FutureTask;
     4 
     5 public class ThirdThread implements Callable<Integer>
     6 
     7 {
     8 
     9 //实现call()方法,作为线程的执行体
    10 
    11 public Integer call(){
    12 
    13 int i=0;
    14 
    15 for( ;i<20;i++){
    16 
    17 System.out.println(Thread.currentThread().getName()+"的循环变量 i的值为:"+i);
    18 
    19 }
    20 
    21 return i;
    22 
    23 }
    24 
    25 public static void main(String[] args){
    26 
    27 //创建Callable 对象
    28 
    29 ThirdThread rt=new ThirdThread();
    30 
    31 //使用FutureTask来包装Callable对象
    32 
    33 FutureTask<Integer> task= new FutureTask<Integer>(rt);
    34 
    35 for(int i=0 ;i<20;i++){
    36 
    37 System.out.println(Thread.currentThread().getName()+"的循环变量为:"+i);
    38 
    39 if(i==5){
    40 
    41 //开始线程
    42 
    43 new Thread(task,"有返回值的线程").start();
    44 
    45 }
    46 
    47 }try
    48 
    49 {
    50 
    51 System.out.println("子线程的返回值为:"+task.get());
    52 
    53 }
    54 
    55 catch (Exception e)
    56 
    57 {
    58 
    59 e.printStackTrace();
    60 
    61 }
    62 
    63 }
    64 
    65  
    66 
    67 }
    View Code

    记住需要import java.util.concurrent.Callable;  import java.util.concurrent.FutureTask;

    程序最后调用FutureTask 对象的get方法来返回call方法的返回值------该方法将导致主线程被阻塞,直到call方法结束并返回为止。

    如果代码为下面这样:

     1 import java.util.concurrent.Callable;
     2 
     3 import java.util.concurrent.FutureTask;
     4 
     5 public class ThirdThread implements Callable<Integer>
     6 
     7 {
     8 
     9 //实现call()方法,作为线程的执行体
    10 
    11 public Integer call(){
    12 
    13 int i=0;
    14 
    15 for( ;i<20;i++){
    16 
    17 System.out.println(Thread.currentThread().getName()+"的循环变量 i的值为:"+i);
    18 
    19 }
    20 
    21 return i;
    22 
    23 }
    24 
    25 public static void main(String[] args){
    26 
    27 //创建Callable 对象
    28 
    29 ThirdThread rt=new ThirdThread();
    30 
    31 //使用FutureTask来包装Callable对象
    32 
    33 FutureTask<Integer> task= new FutureTask<Integer>(rt);
    34 
    35 for(int i=0 ;i<20;i++){
    36 
    37 System.out.println(Thread.currentThread().getName()+"的循环变量为:"+i);
    38 
    39 if(i==5){
    40 
    41 //开始线程
    42 
    43 new Thread(task,"有返回值的线程").start();
    44 
    45 try{
    46 
    47 System.out.println("子线程的返回值为:"+task.get());
    48 
    49 }
    50 
    51 catch (Exception e)
    52 
    53 {
    54 
    55 e.printStackTrace();
    56 
    57 }
    58 
    59 }
    60 
    61  
    62 
    63 }
    64 
    65 }
    66 
    67  
    68 
    69 }

    那么输出结果为:

    main的循环变量为:0

    main的循环变量为:1

    main的循环变量为:2

    main的循环变量为:3

    main的循环变量为:4

    main的循环变量为:5

    有返回值的线程的循环变量 i的值为:0

    有返回值的线程的循环变量 i的值为:1

    有返回值的线程的循环变量 i的值为:2

    有返回值的线程的循环变量 i的值为:3

    有返回值的线程的循环变量 i的值为:4

    有返回值的线程的循环变量 i的值为:5

    有返回值的线程的循环变量 i的值为:6

    有返回值的线程的循环变量 i的值为:7

    有返回值的线程的循环变量 i的值为:8

    有返回值的线程的循环变量 i的值为:9

    有返回值的线程的循环变量 i的值为:10

    有返回值的线程的循环变量 i的值为:11

    有返回值的线程的循环变量 i的值为:12

    有返回值的线程的循环变量 i的值为:13

    有返回值的线程的循环变量 i的值为:14

    有返回值的线程的循环变量 i的值为:15

    有返回值的线程的循环变量 i的值为:16

    有返回值的线程的循环变量 i的值为:17

    有返回值的线程的循环变量 i的值为:18

    有返回值的线程的循环变量 i的值为:19

    子线程的返回值为:20

    main的循环变量为:6

    main的循环变量为:7

    main的循环变量为:8

    main的循环变量为:9

    main的循环变量为:10

    main的循环变量为:11

    main的循环变量为:12

    main的循环变量为:13

    main的循环变量为:14

    main的循环变量为:15

    main的循环变量为:16

    main的循环变量为:17

    main的循环变量为:18

    main的循环变量为:19

    也就验证了上面的情况  get方法会使主线程阻断。直到call方法结束后。才调用主线程。

    创建线程的三种方式对比:

    采用实现Runnable Callable 接口的方式创建多线程——

    线程类只是实现了Runnable 接口或Callable 接口 ,还可以继承其他类。

    在这种方式下,多线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU 、代码、和数据分开。

    劣势是:编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThred()方法。

    采用继承Thread类的方式创建多线程————

    优势:编写简单,如果需要访问当前线程,则无须使用Thread.currentThread()方法。直接使用this 即可获得当前线程。

    劣势:因为线程只能继承一个父类。所以它继承了Thread 不能在继承其他的父类了。

  • 相关阅读:
    dubbo服务集群
    Caused by: java.sql.SQLException: No value specified for parameter 2
    logstash 解析windows iis日志
    maven fastdfs_client.jar找不到问题解决
    logstsha 发送数据到数据节点
    redis被黑客入侵
    logstash 自定义正则
    Caused by: java.sql.SQLException: Generated keys not requested
    BeanFactory not initialized or already closed
    Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/maven/cli/MavenCli : U
  • 原文地址:https://www.cnblogs.com/teng-IT/p/4439084.html
Copyright © 2011-2022 走看看