资讯专栏INFORMATION COLUMN

Java多线程的实现

marek / 3509人阅读

摘要:多线程的实现用多线程只有一个目的更好的利用资源烧水的例子当洗杯子花分钟线程要停分钟等待返回结果才能进行后续的烧水操作,新开一个线程执行洗杯子操作。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。

Java多线程的实现

用多线程只有一个目的:更好的利用cpu资源.烧水的例子.(当洗杯子花5分钟,线程要停5分钟等待返回结果才能进行后续的烧水操作,新开一个线程执行洗杯子操作)。

一、关于线程的一些概念

cpu时间片:我们操作系统看起来可以多个程序同时运行.分时操作系统,将时间分成长短相同的时间区域,分配给一个线程使用,当线程还没有结束,时间片已经过去,该线程只有先停止,等待下一个时间片.cpu运行很快,中间的停顿感觉不出来.

多线程:指的是这个程序(一个进程)运行时产生了不止一个线程(比如,下载程序,开启多个线程同时进行.)

并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力.

线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果.

Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能.

二、Java多线程的实现

1、继承Thread类创建线程

Thread类本质上是实现了Runnable接口,启动该线程的唯一方法是start()方法,

public class MyThread extends Thread{
    //普通的调用方法,定义任务要完成的工作.
    @Override
    public void run() {
        System.out.println("新线程正在执行,处理相关的逻辑!");
    }
}


public class Test {
    public static void main(String[] args) {
        //实例化对象
        MyThread myThread1 = new MyThread();  
        MyThread myThread2 = new MyThread();    
        //开启新的线程,分配新的资源
        myThread1.start();
        myThread2.start();
    }
}

2、实现Runnable接口创建线程

java中是单继承的,如果继承了一个类,就不能直接继承Thread类,需要实现Runnable接口的方式达到开启新线程的目的.

public class MyThread implements Runnable {
    //普通的调用方法,定义任务要完成的工作.
    @Override
    public void run() {
        System.out.println("新线程正在执行,处理相关的逻辑!");
    }    
 }
 
 
 public class Test {
    public static void main(String[] args) {
         MyThread myThread = new MyThread();  
        Thread thread =new Thread(myThread);
        //开启新的线程,分配新的资源
        thread.start();
    }
}

3、实现Callable接口

Callable接口的call()方法类似run()方法,都是定义任务要完成的工作.主要不同点是call()方法是有返回值的、可以抛出异常。Callable类型的任务可以有两种方法开启执行.

方法一:借助FutureTask执行(FutureTask、Callable)

将Callable接口对象放到FutureTask对象中,FutureTask的get()方法,可以获取返回值.

public class MyCallableTask  implements Callable {
    @Override
    public Integer call() throws Exception {
        System.out.println("新线程正在执行,处理相关的逻辑!");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++) {
            sum += i;
        }
        return sum;
    }    
}

    
public class Test {
    public static void main(String[] args) {
        Callable mycallabletask = new MyCallableTask();   
        //由Callable创建一个FutureTask对象:   
        FutureTask futuretask = new FutureTask(mycallabletask);   
        //注释:FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future            和Runnable接口。 
        //由FutureTask创建一个Thread对象:   
        Thread oneThread = new Thread(futuretask);
        oneThread.start();
        try {
            //通过futuretask中get()方法可以得到MyCallableTask的call()运行结果.
            //需要使用时获取出来,否则出现堵塞,本线程要等待新线程执行完返回结果才执行
            Integer i = futuretask.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

方法二:借助线程池来运行 (ExecutorService、Callable、Future)

ExecutorService、Callable、Future三个接口实际上都是属于Executor框架。

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get()就可以获取到Callable任务返回的Object了。

public class MyCallableTask  implements Callable {    
    @Override
    public Integer call() throws Exception {
        System.out.println("新线程正在执行,处理相关的逻辑!");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++) {
            sum += i;
        }
        return sum;
    }
}

public class Test {
    public static void main(String[] args) {
        int taskSize = 5;
        //创建线程池
        ExecutorService threadPool = Executors.newCachedThreadPool(taskSize);
        //提交一个Callable任务,返回一个Future类型
        Future future = threadPool.submit(new MyCallableTask());
         try {
            Thread.sleep(3000);//模拟本线程的一些任务
            //获取执行结果get方法是阻塞的
            System.out.println(future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }    
    }
}

采用匿名类直接新建Callable接口

public class Test{
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // 提交一个Callable任务,返回一个Future类型
        Future future = threadPool.submit(new Callable() {
            @Override
            public Integer call() throws Exception {
                System.out.println("新线程正在执行,处理相关的逻辑!");
                Thread.sleep(3000);
                int sum = 0;
                for (int i = 0; i < 100; i++) {
                    sum += i;
                }
                return sum;
            }
        });

        try {
            Thread.sleep(3000);//模拟本线程的一些任务
            //获取执行结果
            System.out.println(future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


三、使用场景

一、Tomcat内部采用了多线程,上百个用户同时访问同一个web应用,都会新开一个线程,调用到Servlet程序。如果不使用多线程,将串行操作,客户端将等待别人执行完才能访问。

二、异步请求,有两个任务Task a和Task b,单线程只能先进行a再进行b。

三、需要知道执行进度,比如说我们常看到的进度条,任务执行到一定进度给new 一个变量,给变量+1.新开一个线程去轮询这个变量,反馈给客户端,这样就可以看到进度情况.

总之,很多地方都用到了多线程,多线程是为了充分利用cpu资源,当你发现一个业务逻辑执行效率特别低,耗时长,可以考虑使用多线程.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69185.html

相关文章

  • 学习Java线程一些总结

    摘要:多线程环境下的一些问题安全性问题在没有正确同步的情况下,多线程环境下程序可能得出错误的结果。一些相关概念竞争条件多线程的环境下,程序执行的结果取决于线程交替执行的方式。而线程的交替操作顺序是不可预测的,如此程序执行的结果也是不可预测的。 入口 Java多线程的应用复杂性之如jvm有限的几个内存方面的操作和规范,就像无数纷繁复杂的应用逻辑建立在有限的指令集上。 如何写出线程安全的程序,有...

    coolpail 评论0 收藏0
  • JAVA 线程和并发基础

    摘要:线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。在的线程中并没有可供任何对象使用的锁和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻译:并发编程网 - 郑旭东 校对:方腾飞 多...

    vboy1010 评论0 收藏0
  • Java线程学习(七)并发编程中一些问题

    摘要:相比与其他操作系统包括其他类系统有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。因为多线程竞争锁时会引起上下文切换。减少线程的使用。很多编程语言中都有协程。所以如何避免死锁的产生,在我们使用并发编程时至关重要。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)syn...

    dingding199389 评论0 收藏0
  • JAVA 线程和并发基础面试问答

    摘要:多线程和并发问题是技术面试中面试官比较喜欢问的问题之一。线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。 多线程和并发问题是 Java 技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题。(...

    dreamans 评论0 收藏0
  • Java线程学习(七)并发编程中一些问题

    摘要:因为多线程竞争锁时会引起上下文切换。减少线程的使用。举个例子如果说服务器的带宽只有,某个资源的下载速度是,系统启动个线程下载该资源并不会导致下载速度编程,所以在并发编程时,需要考虑这些资源的限制。 最近私下做一项目,一bug几日未解决,总惶恐。一日顿悟,bug不可怕,怕的是项目不存在bug,与其惧怕,何不与其刚正面。 系列文章传送门: Java多线程学习(一)Java多线程入门 Jav...

    yimo 评论0 收藏0
  • 线程三分钟就可以入个门了!

    摘要:系统级线程核心级线程由操作系统内核进行管理。值得注意的是多线程的存在,不是提高程序的执行速度。实现多线程上面说了一大堆基础,理解完的话。虚拟机的启动是单线程的还是多线程的是多线程的。 前言 之前花了一个星期回顾了Java集合: Collection总览 List集合就这么简单【源码剖析】 Map集合、散列表、红黑树介绍 HashMap就是这么简单【源码剖析】 LinkedHashMa...

    awkj 评论0 收藏0

发表评论

0条评论

marek

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<