java实现/创建线程的几种方式小结

进程与线程

进程可以简单理解成一个可执行程序例如.exe,在Windows中的任务管理器中可以查看每一个进程,进程是一次程序的执行,是程序在数据集合上运行的过程,是系统资源调度的一个单位。进程主要负责向操作系统申请资源。然而一个进程中,多个线程可以共享进程中相同的内存或文件资源。线程就是一个进程一个程序要完成所依赖的子任务,这些子任务便可以看作是一个线程。

第一种方式继承Thread类

从java源码可以看出Thread类本质上实现了Runnable接口的实例类,代表了线程的一个线程的实例,启动的线程唯一办法就是通过Thread类调用start()方法,start()方法是需要本地操作系统的支持,它将启动一个新的线程,并且执行run()方法。

继承Thread类实现线程代码如下

创建一个Thread类,对象直接调用run方法会出现什么问题?

package cn.thread.线程;

public class MyThread extends Thread{
    public MyThread(String name){
        super(null,null,name);
    }
    int piao =10;
    @Override
    public void run() {
        while(piao>0){
            System.out.println(Thread.currentThread().getName()+"......"+piao--);
        }
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread("x");
        mt.run();
    }
}

结果:

可以发现是主线程执行了run方法,并不是用户线程执行的run方法,此时可以得出用户线程并没有启动,所以并不会执行run里面的方法,且执行完run方法便结束线程。

第二种创建线程的方法,实现Runnable接口

相比继承Thread类而言,实现接口的可扩展性得到了提升,Runnable接口也必须要封装到Thread类里面,才可以调用start方法,启动线程。

实现代码

package cn.thread.线程;

public class MyRunnable implements Runnable{

    int piao = 10;
    @Override
    public void run() {
        while(piao>0){
            System.out.println(Thread.currentThread().getName()+"-----"+piao--);
        }
    }

    public static void main(String[] args) {
        Runnable r =new MyRunnable();
        Thread t =new Thread(r);
        t.start();
    }

}

结果

第三种创建线程的方法实现Callable接口

Callable接口使用方法和Runnable接口的方法类似不同的一点是Callable接口具有返回值,返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。 Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。

实现代码

对下列代码进行分析

首先callable是接口不能直接创建对象,也不能创建线程。并且要实现call方法类似run方法的功能,call方法有返回值,会计算结果,如果无法计算结果,则抛出一个异常。

执行callable任务之后,可以获得一个future的对象,future基本上是主线程可以跟踪进度以及获取其他线程结果的一种方式。在这里Test1()方法主要利用线程池和future的方法,去启动实现Callable接口的线程,具有返回值。而Test2()主要是采用FutureTask类去实现创建一个实现callable接口的线程,futuretask实现了future接口。

package com.openlab.test;

import java.util.Random;
import java.util.concurrent.Callable;

public class CallableTest implements Callable{

	@Override
	public Object call() throws Exception {

		Random generator = new Random();

		Integer randomNumber = generator.nextInt(5);

		Thread.sleep(randomNumber*1000);

		return randomNumber;
	}

}

综合练习代码:

package cn.thread.线程;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

public class CallableTest implements Callable<Object> {//不能直接创建线程
    int taskNum;
    public CallableTest(int taskNum){
        this.taskNum = taskNum;

    }
    @Override
    public Object call() throws Exception {

        System.out.println(">>>"+taskNum+"任务启动");
        Date dataTemp = new Date();
        Thread.sleep(1000);
        Date dataTemp2 = new Date();
        long time  = dataTemp2.getTime() - dataTemp.getTime();
        System.out.println(">>>>"+taskNum+"任务终止");
        return taskNum+"任务返回运行结果"+time;
//        Random generator = new Random();
//        Integer randomNumber = generator.nextInt(5);
//        Thread.sleep(randomNumber*1000);
//        return  randomNumber;
    }
    /*test1方法采用Executors的静态方法newFixedThreadPool(taskSize) 创建一个可重用固定线程集合的
    线程池,以共享的无界队列方式来运行这些线程,获取线程池。ExecutorService的submit方法提交一个
    callable实例,得到一个future对象,最终将future对象存储在list数组中,加入线程池的过程中就代表
    着线程已经开始执行,相当于一个线程池代理过程,就不需要采用start方法启动线程。最后对future进行
    打印输出。切记一定要关闭线程池!*/
     static void test1() throws ExecutionException, InterruptedException {
         System.out.println("程序开始");
         Date data1 = new Date();
         int taskSize = 5;
        //构建线程池对象
         ExecutorService pool = Executors.newFixedThreadPool(taskSize);
         List<Future> list =new ArrayList<Future>();
         for(int i=0;i<taskSize;i++){

             Callable c = new CallableTest(i);
             Future f = pool.submit(c);
             list.add(pool.submit(c));

         }
         //关闭线程池
         pool.shutdown();
         for(Future f:list){
             System.out.println(">>>"+f.get().toString());
         }
         Date date2 = new Date();
         System.out.println("程序运行结束-----"+(date2.getTime()-data1.getTime())+"毫秒");
     }
     /*test2方法主要是采用futuretask类,可以直接把callable作为参数来申明futuretask对象,
     这里相当于把线程池换成了futuretask数组,因为test1线程池可以对callable进行封装,
     在这里可以直接采用futuretask就行封装,在加上futuretask又实现了runnable接口,
     所以可以直接创建线程采用start的方式进行启动线程。*/
     static  void test2() throws ExecutionException, InterruptedException {
         System.out.println("----程序开始-----");
         Date date1 =new Date();
         int taskSize = 5;
         FutureTask[] randNumber = new FutureTask[taskSize];
         List<Future> list =new ArrayList<Future>();
         for(int i=0;i<taskSize;i++){
             Callable c = new CallableTest(i);
             randNumber[i] = new FutureTask(c);
             Thread t = new Thread(randNumber[i]);
             t.start();

         }
         for(Future f:randNumber){
             System.out.println(">>>"+f.get().toString());
         }
         Date date2 = new Date();
         System.out.println("程序运行结束-----"+(date2.getTime()-date1.getTime())+"毫秒");

     }
    public static void main(String[] args) throws Exception {
//        CallableTest c = new CallableTest();
//        Integer i = (Integer) c.call();
        test1();
        test2();

    }
}

执行结果

第四种实现线程的方法,基于线程池

其实在第三种的方法中就提到了两种实现方法,一种线程池+future,另一种futuretask的方法。线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。

// 创建线程池
 ExecutorService threadPool = Executors.newFixedThreadPool(10);
 while(true) {
 threadPool.execute(new Runnable() { // 提交多个线程任务,并执行
 @Override
 public void run() {
 System.out.println(Thread.currentThread().getName() + " is running ..");
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 });
 } }

总结

理论上实现线程的方法还有一些,本文所提及到的,基本都是一些创建线程常用的方法。希望本文对大家在学习线程的过程中有所帮助。

(0)

相关推荐

  • Java 线程池详解及创建简单实例

    Java 线程池 最近在改进项目的并发功能,但开发起来磕磕碰碰的.看了好多资料,总算加深了认识.于是打算配合查看源代码,总结并发编程的原理. 准备从用得最多的线程池开始,围绕创建.执行.关闭认识线程池整个生命周期的实现原理.后续再研究原子变量.并发容器.阻塞队列.同步工具.锁等等主题.java.util.concurrent里的并发工具用起来不难,但不能仅仅会用,我们要read the fucking source code,哈哈.顺便说声,我用的JDK是1.8. Executor框架 Exec

  • Java多线程中线程的两种创建方式及比较代码示例

    1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行.当程序作为一个应用程序运行时,java解释器为main()方法启动一个线程. 2.并行与并发: (1)并发:在单处理器系统中,多个线程共享CPU时间,而操作系统负责调度及分配资源给它们. (2)并行:在多处理器系统中,多个处理器可以同时运行多个线程,这些线程在同一时间可以同时运行,而不同于并发,只能多个线程共享CP

  • java 创建线程的几种方式

    说道线程,肯定会想到使用 java.lang.Thread.java这个类 那么创建线程也主要有2种方式 第一种方式: public class MyThread extends Thread { public void run() { System.out.println("这是MyThread线程"); } } 然后在调用处,执行start方法即可: MyThread myThread = new MyThread(); myThread.start(); 第二种方式实现Runna

  • 创建并运行一个java线程方法介绍

    要解释线程,就必须明白什么是进程. 什么是进程呢? 进程是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间),比如用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间.当用户再次点击左面的IE浏览器,又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间.目前操作系统都支持多进程. 要点:用户每启动一个进程,操作系统就会为该进程分配一个独立的内存空间. 线程--概念 在明白进程后,就比较容易理解线程的概念. 什么是线程呢? 是进程中的一个实体,是被

  • Java创建子线程的两种方法

    摘要: 其实两种方法归结起来看还是一种,都是利用Thread的构造器进行创建,区别就是一种是无参的,一种是有参的. 一.继承Thread线程类: 通过继承Thread类,重写run方法,子类对象就可以调用start方法启动线程,JVM就会调用此线程的run方法. 代码如下: public class MyThread extends Thread { public MyThread() { super(); } @Override public void run() { } // 线程执行结束

  • java创建线程的两种方法区别

    在Java中创建一个线程有两种方法:继承Thread类和实现Runnable接口. 下面通过两个例子来分析两者的区别: 1)继承Thread类 public class TestThread extends Thread { int count = 3; public TestThread(String ThreadName) { super(ThreadName); } @Override public void run() { for (int i = 0; i < 10; i++) if

  • 简单了解Java编程中线程的创建与守护线程

    线程的两种创建方式及优劣比较 1.通过实现Runnable接口线程创建 (1).定义一个类实现Runnable接口,重写接口中的run()方法.在run()方法中加入具体的任务代码或处理逻辑. (2).创建Runnable接口实现类的对象. (3).创建一个Thread类的对象,需要封装前面Runnable接口实现类的对象.(接口可以实现多继承) (4).调用Thread对象的start()方法,启动线程 示例代码: package demo.thread; public class Tread

  • Java创建多线程的两种方式对比

    采用继承Thead类实现多线程: 优势:编写简单,如果需要访问当前线程,只需使用this即可,无需使用Thead.currentThread()方法. 劣势:因为这种线程类已经继承了Thead类,所以不能再继承其它类. 示例代码: 复制代码 代码如下: package org.frzh.thread;    public class FirstThread extends Thread{      private int i;           //重写run方法,run方法的方法体就是线程执

  • Java多线程——之一创建线程的四种方法

    1.实现Runnable接口,重载run(),无返回值 package thread; public class ThreadRunnable implements Runnable { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } package thread; public clas

  • java实现/创建线程的几种方式小结

    进程与线程 进程可以简单理解成一个可执行程序例如.exe,在Windows中的任务管理器中可以查看每一个进程,进程是一次程序的执行,是程序在数据集合上运行的过程,是系统资源调度的一个单位.进程主要负责向操作系统申请资源.然而一个进程中,多个线程可以共享进程中相同的内存或文件资源.线程就是一个进程一个程序要完成所依赖的子任务,这些子任务便可以看作是一个线程. 第一种方式继承Thread类 从java源码可以看出Thread类本质上实现了Runnable接口的实例类,代表了线程的一个线程的实例,启动

  • java 创建线程的四种方式

    1.继承Thread类方式 这种方式适用于执行特定任务,并且需要获取处理后的数据的场景. 举例:一个用于累加数组内数据的和的线程. public class AdditionThread extends Thread { private int sum = 0; private int[] nums; ​ public AdditionThread(int[] nums, String threadName) { super(threadName); this.nums = nums; } ​

  • 关于Java创建线程的2种方式以及对比

    目录 1. 继承Thread类 2. 实现Runnable接口: 创建线程的两种方式对比: 线程的完整生命周期: 总结 Java中两种创建线程的方式: 1. 继承Thread类 重写run()方法 new一个线程对象 调用对象的start()启动线程 class Handler extends Thread{ public void run(){ //重写run()方法 } public static void main(String[] args){ Thread thread=new Han

  • Java中实现线程的三种方式及对比_动力节点Java学院整理

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

  • java多线程之线程同步七种方式代码示例

    为何要使用同步?  java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),     将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,     从而保证了该变量的唯一性和准确性. 1.同步方法  即有synchronized关键字修饰的方法.     由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,     内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就处于阻塞状态.     代码

  • JavaEE的进程,线程和创建线程的5种方式详解

    目录 一.认识进程.线程 1.1什么是进程 进程的调度 并发式执行 1.2认识线程 1.3进程.线程之前的区别和联系(面试题) 创建线程的几种方式 总结 一.认识进程.线程 1.1什么是进程 进程process/task.“进程"是计算机完成一个工作的"过程” 设备上一个正在运行的程序,就是一个进程.比如你打开的QQ就是一个进程,正在和别人聊天的微信也是一个进程.进程是系统进行资源分配的基本单位. 当我们打开任务管理器就可以看到,当前操作系统中正在运行的进程. 要想让一个进程真正的运行

  • Java 数组转List的四种方式小结

    目录 第一种方式(未必最佳):使用ArrayList.asList(strArray) 第二种方法(支持增删查改): 第三种方式(通过集合工具类Collections.addAll()方法(最高效)) 第四种方式通过JDK8的Stream流将3总基本类型数组转为List java数组转list误区 一.不能把基本数据类型转化为列表 二.asList方法返回的是数组的一个视图 第一种方式(未必最佳):使用ArrayList.asList(strArray) ​ 使用Arrays工具类Arrays.

  • Numpy中创建数组的9种方式小结

    目录 1.使用empty方法创建数组 2.使用array创建数组 3.使用zeros/ones创建数组 4.使用arange创建数组 5.使用linspace创建数组 6.使用numpy.random.rand创建数组 7.使用numpy.random.randn创建数组 8.使用numpy.random.randint创建数组 9.使用fromfunction创建数组 1.使用empty方法创建数组 该方式可以创建一个空数组,dtype可以指定随机数的类型,否则随机采用一种类型生成随机数. i

  • Java创建线程的两种方式

    前言 多线程是我们开发过程中经常遇到的,也是必不可少需要掌握的.当我们知道需要进行多线程开发时首先需要知道的自然是如何实现多线程,也就是我们应该如何创建线程. 在Java中创建线程和创建普通的类的对象操作是一样的,我们可以通过两种方式来创建线程: 1.继承Thread类,并重写run()方法. 2.实现Runnable接口,并实现run()方法. 方法一:继承Thread类 代码非常简单 首先重载一个构造函数,以便我们可以给线程命名. 重写run()方法. 这里我们先让线程输出线程名+start

随机推荐