关闭

Java多线程总结

标签: Java多线程
8057人阅读 评论(1) 收藏 举报
分类:

Java多线程是什么

Java提供的并发(同时、独立)处理多个任务的机制。多个线程共存于同一JVM进程里面,所以共用相同的内存空间,较之多进程,多线程之间的通信更轻量级。依我的理解,Java多线程完全就是为了提高CPU的利用率。Java的线程有4种状态,新建(New)、运行(Runnable)、阻塞(Blocked)、结束(Dead),关键就在于阻塞(Blocked),阻塞意味着等待,阻塞的的线程不参与线程分派器(Thread Scheduler)的时间片分配,自然也就不会使用到CPU。多线程环境下,那些非阻塞(Blocked)的线程会运行并充分利用CPU。

Java线程阻塞(Blocked)的类型:

  • 调用sleep函数进入睡眠状态,Thread.sleep(1000)或者TimeUnit.SECONDS.sleep(1)sleep不会释放锁
  • 等待(wait)某个事件,分为两种,(wait,notify,notifyAll),(await, signal,signalAll) ,后面会详细介绍。wait和await会释放锁,且必须在获取到锁的环境才能调用。
  • 等待锁,synchronized和lock环境中,锁已经被别的线程拿走,等待获取锁。
  • IO阻塞(Blocked),比如网络等待,文件打开,控制台读取。System.in.read()

Java多线程的创建

线程驱动任务的处理,涉及到两个概念,线程(Thread)、以及任务(Task, Java里面叫Runnable),推荐的做法是写一个类(class)实现Runnable接口,作为Task,传给Thread的的构造函数,调用Thread的start方法即可。当然你也可以直接继承Thread类,重写(Override)run方法。从任务抽象的角度来说,推荐前者,后者的优势是简单。想创建多个线程,就new多个Thread并start即可。不过JVM有一个最大线程数的限制,-Xssjava命令行非标准可选项可以设置大小,不同平台可能不一样,需要查文档或写代码验证。

Java多线程的资源竞争(race condition)

多个线程同时访问同一份资源(内存块)的时候,可能发生某一个线程处理到一半,被别的线程抢走资源并修改的问题,造成资源的不一致。要避免此类问题,唯一的解决方案就是加锁

Java有两种锁可供选择:

  • 对象或者类(class)的锁。每一个对象或者类都有一个锁。使用synchronized关键字获取。 synchronized加到static方法上面就使用类锁,加到普通方法上面就用对象锁。除此之外synchronized还可以用于锁定关键区域块(Critical Section)。 synchronized之后要制定一个对象(锁的携带者),并把关键区域用大括号包裹起来。synchronized(this){// critical code}
  • 显示构建的锁(java.util.concurrent.locks.Lock),调用lock的lock方法锁定关键代码。

原子性和可见性

  • 原子性(Atomic)是指一个操作处理过程中,CPU(处理控制权) 不会被抢走。处理就会在一个时间片段内处理完毕。Java中两个double数字相加这样一条语句都不具有原子性。
  • 可见性(visibility)是指多个线程之间看到完全相同的资源,任何线程对资源的修改,其它线程都能够实时看到。synchronized能够保证资源的可见性 , volatile关键字也能够保证资源的可见性。

Java多线程之间的合作

Java多线程共享相同的内存,自然可以通过访问和修改同一份资源(对象)来交互和通信,只是需要注意线程的安全性。此外,Java还提供一些其它的线程交互方式,绝大多数都通过线程分派器(Thread Scheduler)完成。主要的一些交互方式如下:

yield

提示线程分派器(Thread Scheduler)当前线程已经完成一个完整的工作,此时是一个切换到其它线程的好时机。通常这可以提高切换的可能,但是需要注意切换只是可能,不是一定发生。所以业务不能完全依赖于yield。Thread.yield()

join

暂停当前线程的运行,等待另外一个线程运行完毕之后再继续运行。anotherThread.join()。这种依赖关系可以得到保证。依个人的理解,此时当前线程也是被阻塞(Blocked)了,等待另外一个线程运行完毕,然后唤醒。join会抛出InterruptedException(间接证明当前线程被Blocked),当前线程调用interrupt方法会解除依赖,并抛出InterruptedException。

wait notify notifyAll

这三个都是Object的方法,wait用来阻塞(Block)当前线程,但是会释放对象的锁,notify告诉线程分派器唤醒等待的某一个线程,notifyAll会唤醒所有等待的线程。需要特别注意的是,这三个方法都需要在锁定的环境(synchronized)里面使用,否则编译通过,但是运行报错。wait notify notifyAll 与 synchronized配对使用。

while(conditionIsNotSatisfied)
    wait()

await signal signalAll

await signal signalAll是java.util.concurrent.locks.Condition的三个方法,Condition可以通过Lock获得Condition condition = lock.newCondition()。从功能上来说,await signal signalAll与wait notify notifyAll应该是相同的,只是await signal signalAll与Condition配对使用。

while(conditionIsNotSatisfied)
    condition.await()

取消线程的运行

推荐的做法是调用线程的interrupt方法。线程也有stop函数,不过JDK1.5以后被弃用了,原因据说是因为会引起死锁。所有会抛出InterruptedException的线程阻塞都可以调用interrupt方法唤醒,不过是通过异常的方式退出,如果需要释放资源,一定要使用try finally语句。IO的阻塞、synchronized阻塞、lock阻塞都无法使用interrupt方法唤醒。IO阻塞可以通过关闭(close)资源的方式退出。如果是非阻塞的线程,需要检测interrupt状态,有两个方法,isInterrupted和interrupted,interrupted有副作用,会清理状态。标准的能够响应interrupt的程序格式大概如下:


  public void run(){
    try{
        // check interrupt status
        while(!Thread.interrupted()){
            // declare resource
            try{
                // use resource
            }catch(Exception e){
                // release resource
            }
        }
    }catch(InterruptedException ex){
        // do something when InterruptedException triggered.
    }
}

后记

  • Java的线程是阻塞(同步)的,优点是顺序执行,易于编写和理解。有些场景下需要借助多线程才能提高运行效率。
  • 最近两年非常火Node.js是非阻塞的,事件驱动,效率非常高,但是Node.js也非银弹,攻无不克,它是单线程的, 在手机都8核的年代里面,单线程会有CPU利用不足的问题。可能的一个解法是多进程,启动多个Node.js实例。 另外一个问题是代码的可读性会比较差一些,容易出现多次嵌套的结构。
  • 函数式编程,永远不会改变参数的值,没有全局变量,没有副作用,天然的是线程安全的。看起来像银弹,但是 函数式编程的门槛比较高,推广会是个问题。
17
0
查看评论

多线程笔记总结

多线程笔记总结1、Java中如果我们自己没有产生线程,那么系统就会给我产生一个线程(主线程,main方法就是在主线程上运行),我们的程序都是由线程来执行的。 2、进程:执行中的程序(程序是静态的概念、进程是动态的概念)。 3、线程的实现由两种方式,第一种方式是继承Thread类,然后重写方法;第二种...
  • nicewuranran
  • nicewuranran
  • 2016-04-07 15:00
  • 378

多线程总结

<br />进入run()函数后,新线程就开始运行,有自己的堆栈。<br />出了run()函数后,新建的线程就结束,并会发出信号,可以在另外一个线程中捕获,然后响应。、<br /> currentThreadId()和currentThread()分别...
  • xie376450483
  • xie376450483
  • 2010-11-12 20:59
  • 3494

Java多线程学习(吐血超详细总结)

本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。
  • Evankaka
  • Evankaka
  • 2015-03-14 13:13
  • 71026

Java多线程学习(吐血超详细总结)

转自:http://www.mamicode.com/info-detail-517008.html 目录(?)[-] 一扩展javalangThread类二实现javalangRunnable接口三Thread和Runnable的区别四线程状态转换五线程调度六常用函数说明 使...
  • gf771115
  • gf771115
  • 2016-06-15 15:15
  • 41819

Java多线程编程总结

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/27069 下面是Java线程系列博文的一个编目:   Java线程:概念与原理 Java线程:创建与启动 Java线程:线程...
  • liuwenbo0920
  • liuwenbo0920
  • 2015-01-10 13:21
  • 965

Java多线程面试常见核心问题总结

1. 有T1、T2、T3三个线程,如何怎样保证T2在T1执行完后执行,T3在T2执行完后执行?         使用join方法。         join方法的功能是使异步执行的线程变成同步执行。即调用线程实例的sta...
  • HiJson
  • HiJson
  • 2016-10-21 22:22
  • 6611

Java多线程并发总结

Java多线程1.实现方式: 继承Thread,实现Runnable接口 Thread类,继承不灵活,不能资源共享 Runnable是接口,灵活且实现资源共享 注:线程在调用方法时,如果方法内部使用了全局变量(含...
  • a466350665
  • a466350665
  • 2015-10-16 13:16
  • 572

java多线程总结五:线程池的原理及实现

1、线程池简介:     多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。        假设一个服务器完成一项任务所需时间为:T1 创建线...
  • Touch_2011
  • Touch_2011
  • 2011-10-28 14:46
  • 66491

多线程的总结

学了很久的java,但是一直对多线程这块知识不是很熟悉,看了以上博客决定来做个多线程总结,首先立个列表: 多线程零零碎碎的各种概念知识 死锁和数据不一致的现象 synchronized 和 volatile 的区别 synchtonized 和 Reentran...
  • m0_37897828
  • m0_37897828
  • 2017-08-12 10:34
  • 327

多线程心得

Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。具体看代码: public class JoinTest { public static void main(String [] args) throws InterruptedExceptio...
  • m0_37383637
  • m0_37383637
  • 2018-02-02 18:34
  • 8
    个人资料
    • 访问:725843次
    • 积分:6280
    • 等级:
    • 排名:第4650名
    • 原创:75篇
    • 转载:0篇
    • 译文:6篇
    • 评论:166条
    博客专栏
    文章分类
    最新评论