java多进程、多线程讲解

一、 什么是进程、线程?线程和进程的区别?

1. 进程 当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序。 进程是操作系统进行资源分配和调度的一个独立单位。 进程的三个特征:

  • 独立性 独立存在的实体,每个进程都有自己独立私有的一块内存空间。
  • 动态性 程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。
  • 并发性 多个进程可在单处理器上并发执行。
并发性和并行性
并发是指在同一时间点只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
并行指在同一时间点,有多条指令在多个处理器上同时执行。

2. 线程 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。线程也被称作轻量级进程。线程在进程中是独立,并发的执行流。

3.线程和进程的区别

  1. 线程是进程的组成部分,一个进程可以有很多线程,每条线程并行执行不同的任务。
  2. 不同的进程使用不同的内存空间,而线程与父进程的其他线程共享父进程的所拥有的全部资源。这样编程方便了,但是要更加小心。
  3. 别把内存空间和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。线程拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源。
  4. 线程的调度和管理由进程本身负责完成。操作系统对进程进行调度,管理和资源分配。

二、 多线程的优势

  1. 进程之间不能共享内存,但线程之间共享内存。
  2. 系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小很多,效率高。
  3. 资源利用率更好
  4. 程序设计更简单
  5. 程序响应更快 后三条详细见http://ifeve.com/benefits/

三、 Java中创建线程方法

1. 继承Thread类创建线程类

  1. 定义Thread类的子类,重写该类的run()方法。该方法为线程执行体。
  2. 创建Thread子类的实例。即线程对象。
  3. 调用线程对象的start()方法启动该线程

2. 实现Runnable接口创建线程类

  • 定义Runnable接口的实现类,重写该接口的run()方法。该方法为线程执行体。
  • 创建Runnable实现类的实例。并以此实例作为Thread的target来创建Thread对象。该Thread对象才是真正的线程对象。
  • 调用线程对象(该Thread对象)的start()方法启动该线程。

3. 使用Callable和Future创建线程http://blog.csdn.net/ghsau/article/details/7451464


四、 用Runnable还是ThreadJava以及创建线程两种方法对比?

在java多线程中,一般推荐采用实现Runnable接口来创建多线程,因为实现Runnable接口相比继承Thread类有如下优劣势:

  • 实现Runnable接口,线程类只是实现了接口,还可以继承其他类;继承Thread类的话,不能再继承其他父类。
  • 实现Runnable接口,多个线程可以共享同一个target对象,所以适合多个相同程序代码的线程区处理同一资源的情况。分离数据和代码,体现面向对象的思想。
  • 实现Runnable接口,访问当前线程,必须使用Thread.currentThread()方法;继承Thread类的话,使用this获得当前线程。 与http://blog.csdn.net/ns_code/article/details/17161237互补。

五、 Thread 类中的start() 和 run() 方法有什么区别?

  1. start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。
  2. 当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。 需要特别注意的是:不能对同一线程对象两次调用start()方法。

六、 线程的生命周期

Java线程五种状态:

  1. 新建状态(New):当线程对象创建后,即进入了新建状态。仅仅由java虚拟机分配内存,并初始化。如:Thread t = new MyThread();
  2. 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,java虚拟机创建方法调用栈和程序计数器,只是说明此线程已经做好了准备,随时等待CPU调度执行,此线程并 没有执行。
  3. 运行状态(Running):当CPU开始调度处于就绪状态的线程时,执行run()方法,此时线程才得以真正执行,即进入到运行状态。注:绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  4. 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    1. 等待阻塞 – 运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态,JVM会把该线程放入等待池中;
    2. 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    3. 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead):线程run()方法执行完了或者因异常退出了run()方法,该线程结束生命周期。 当主线程结束时,其他线程不受任何影响。

七、 java控制线程方法

1. join线程 join方法用线程对象调用,如果在一个线程A中调用另一个线程B的join方法,线程A将会等待线程B执行完毕后再执行。

2. 守护线程(Daemon Thread) Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。 用户线程即运行在前台的线程,而守护线程是运行在后台的线程。 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,VM就不会退出。 守护线程的特征:如果所有前台线程都死亡,后台线程会自动死亡。 守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程。 虽然守护线程可能非常有用,但必须小心确保其他所有非守护线程消亡时,不会由于它的终止而产生任何危害。因为你不可能知道在所有的用户线程退出运行前,守护线程是否已经完成了预期的服务任务。一旦所有的用户线程退出了,虚拟机也就退出运行了。 因此,不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。 另外有几点需要注意:

1、setDaemon(true)必须在调用线程的start()方法之前设置,否则会跑出IllegalThreadStateException异常。
2、在守护线程中产生的新线程也是守护线程。  
3、 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑。 

参考http://blog.csdn.net/ns_code/article/details/17099981

3. 线程让步(yield ) yield可以直接用Thread类调用,可以让当前正在执行的线程暂停,不会阻塞该线程,只是将该线程转入就绪状态。yield让出CPU执行权给同等级的线程,如果没有相同级别的线程在等待CPU的执行权,则该线程继续执行。


八、 sleep()方法和yield()方法的区别

  1. sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同,或优先级更高的线程执行机会。
  2. sleep()方法会将线程转入阻塞状态(block状态),直到经过阻塞时间才会转入就绪状态;而yield()方法不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。 因此完全有可能某个线程调用yield()方法暂停之后,立即再次获得处理器资源被执行。
  3. sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要么捕捉该异常,要么显式声明抛出该异常;而yield()方法则没有声明抛出任何异常。
  4. sleep()方法比yield()方法有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行。

九、 为什么Thread类的sleep()和yield()方法是静态的?

Thread类的sleep()和yield()方法将在当前正在执行的线程上运行。所以在其他处于等待状态的线程上调用这些方法是没有意义的。它们可以在当前正在执行的线程中工作,并避免程序员错误的认为可以在其他非运行线程调用这些方法。 现在的实现, 是只能sleep当前的线程.当前线程是自愿的.让sleep()成为实例方法, 当前线程可以直接sleep别的线程, 会引入很多 多线程问题,例如死锁。 destroy(), suspend(), stop(),resume()这些实例方法都已经被deprecated(弃用)。活下来的是哪些? 只有static方法(只对当前线程操作和一些比较温和的实例方法, 如getXXX(), isXXX(), join(), yield()等.


十、 sleep方法与wait方法的区别?

  1. sleep方法是静态方法,wait方法是非静态方法。
  2. sleep方法在时间到后会自己“醒来”,但wait不能,必须由其它线程通过notify(All)方法让它“醒来”。
  3. sleep方法通常用在不需要等待资源情况下的阻塞,像等待线程、数据库连接的情况一般用wait。

十一、 线程安全问题

线程安全问题,其实是指多线程环境下对共享资源的访问可能会引起此共享资源的不一致性。因此,为避免线程安全问题,应该避免多线程环境下对此共享资源的并发访问。


十二、 同步代码块

同步代码块的格式为:

 synchronized (obj) {             
//...
}

其中,obj为锁对象,因此,选择哪一个对象作为锁是至关重要的。一般情况下,都是选择此共享资源对象作为锁对象。 任何时刻只能有一个线程可以获得对锁对象的锁定,其他线程无法获得锁,也无法修改它。当同步代码块执行完成后,该线程会释放对锁对象的锁定。 通过这种方式可以保证并发线程在任一时刻只有一个线程可以进入修改共享资源的代码区(临界区),从而保证线程的安全性。


十三、 同步方法

对共享资源进行访问的方法定义中加上synchronized关键字修饰,使得此方法称为同步方法。可以简单理解成对此方法进行了加锁,其锁对象为当前方法所在的对象自身。多线程环境下,当执行此方法时,首先都要获得此同步锁(且同时最多只有一个线程能够获得),只有当线程执行完此同步方法后,才会释放锁对象,其他的线程才有可能获取此同步锁,以此类推…


public synchronized void a() {        
// ....
}

可变类的线程安全是以降低程序的运行效率为代价的,为了减少程序安全所带来的负面影响,程序可以采用如下策略: – 不要对线程安全类的所有方法都进行同步,只对那些会改变竞争资源的方法进行同步。 – 如果可变类有两种运行环境:单线程和多线程环境,则应该为该可变类提供两种版本:线程不安全版本和线程安全版本。在单线程环境中使用线程不安全版本以保证性能,在多线程环境中使用线程安全版本。


十四、 何时会释放对同步监视器锁定?

程序无法显式的释放对同步监视器的锁定,线程可以通过以下方式释放锁定: A、当线程的同步方法、同步代码库执行结束,就可以释放同步监视器 B、当线程在同步代码库、方法中遇到break、return终止代码的运行,也可释放 C、当线程在同步代码库、同步方法中遇到未处理的Error、Exception,导致该代码结束也可释放同步监视器 D、当线程在同步代码库、同步方法中,程序执行了同步监视器对象的wait方法,导致方法暂停,释放同步监视器

下面情况不会释放同步监视器:
A、当线程在执行同步代码库、同步方法时,程序调用了Thread.sleep()/Thread.yield()方法来暂停当前程序,当前程序不会释放同步监视器
B、当线程在执行同步代码库、同步方法时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放同步监视器。注意尽量避免使用suspend、resume

十五、同步锁(Lock)

通常认为:Lock提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock更灵活的结构,有很大的差别,并且可以支持多个Condition对象 Lock是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁, 线程开始访问共享资源之前应先获得Lock对象。不过某些锁支持共享资源的并发访问,如:ReadWriteLock(读写锁),在线程安全控制中, 通常使用ReentrantLock(可重入锁)。使用该Lock对象可以显示加锁、释放锁。

    class C {
//锁对象
private final ReentrantLock lock = new ReentrantLock();
......
//保证线程安全方法
public void method() {
//上锁
lock.lock();
try {
//保证线程安全操作代码
} catch() {
} finally {
lock.unlock();//释放锁
}
}
}

使用Lock对象进行同步时,锁定和释放锁时注意把释放锁放在finally中保证一定能够执行。使用锁和使用同步很类似,只是使用Lock时显示的调用lock方法来同步。而使用同步方法synchronized时系统会隐式使用当前对象作为同步监视器,同样都是“加锁->访问->释放锁”的操作模式,都可以保证只能有一个线程操作资源。 同步方法和同步代码块使用与竞争资源相关的、隐式的同步监视器,并且强制要求加锁和释放锁要出现在一个块结构中,而且获得多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的范围内释放所有资源。 Lock提供了同步方法和同步代码库没有的其他功能,包括用于非块结构的tryLock方法,已经试图获取可中断锁lockInterruptibly()方法, 还有获取超时失效锁的tryLock(long, timeUnit)方法。 ReentrantLock具有重入性,也就是说线程可以对它已经加锁的ReentrantLock再次加锁,ReentrantLock对象会维持一个计数器来追踪lock方法的嵌套调用,线程在每次调用lock()加锁后,必须显示的调用unlock()来释放锁,所以一段被保护的代码可以调用另一个被相同锁保护的方法。


十六、死锁

当2个线程相互等待对方是否同步监视器时就会发生死锁,JVM没有采取处理死锁的措施,这需要我们自己处理或避免死锁。 一旦死锁,整个程序既不会出现异常,也不会出现错误和提示,只是线程将处于阻塞状态,无法继续。 由于Thread类的suspend也很容易导致死锁,所以Java不推荐使用此方法暂停线程。 参考http://ifeve.com/deadlock/了解更多死锁情况。 大部分代码并不容易产生死锁,死锁可能在代码中隐藏相当长的时间,等待不常见的条件地发生,但即使是很小的概率,一旦发生,便可能造成毁灭性的破坏。避免死锁是一件困难的事,遵循以下原则有助于规避死锁

 1、只在必要的最短时间内持有锁,考虑使用同步语句块代替整个同步方法;
2、尽量编写不在同一时刻需要持有多个锁的代码,如果不可避免,则确保线程持有第二个锁的时间尽量短暂;
3、创建和使用一个大锁来代替若干小锁,并把这个锁用于互斥,而不是用作单个对象的对象级别锁;

参考:http://blog.csdn.net/ns_code/article/details/17200937


这些我都是看书,以及参考网络资料总结的。接下来还会总结线程通信,线程池和线程安全集合类相关知识点。我会在本博文更新~ 参考:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ http://ifeve.com/java-concurrency-thread-directory/ http://www.importnew.com/12773.html http://www.cnblogs.com/lwbqqyumidi/p/3804883.html java编程思想 java疯狂讲义 http://blog.csdn.net/zhoubin1992/article/details/46861397

转载请注明:Android开发中文站 » Java多线程和并发性知识点总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293849.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fstream实现文件复制(并将文件名小写改成大写)

使用C的fstream类来实现char* filename "C:\\grldr.mbr";//须复制文件路径 int len strlen(filename); while( *(filenamelen-1)!\\){ len--; }//获得文件名 char temp[32]; strcpy(temp,(filenamelen)); for (int i 0; i<s…

AsyncHttpClient的连接池使用逻辑

AsyncHttpClient的连接池结构很简单, NettyConnectionsPool内部重要的几个变量如下 // 连接池, 通过 host 区分不同的池private final ConcurrentHashMap<String, ConcurrentLinkedQueue<IdleChannel>> connectionsPool new ConcurrentHashMap<String, Concurr…

记录一次C#爬虫记录,获取必应图片

起因事情是这样的&#xff0c;我创建了一个仓库&#xff0c;里面有2018年到目前为止每日的必应壁纸&#xff0c;在八月份的时候我看到微软有接口文档&#xff0c;于是写了一个服务&#xff0c;每天早上八点钟会获取必应壁纸&#xff08;目前已经可以作为api来使用了&#xff0c…

word打出计算机图形符号,在word插入符号和特殊符号-word技巧-电脑技巧收藏家

在word插入符号和特殊符号打开“插入”菜单&#xff0c;单击“特殊字符”命令&#xff0c;打开“插入特殊符号”对话框&#xff0c;在这个对话框中有六个选项卡&#xff0c;分别列出了六类不同的特殊符号&#xff1b;从列表中选择要插入的特殊字符&#xff0c;单击“确定”按钮…

Android插件化开发基础之静态代理模式

一 Proxy模式 意图&#xff1a; 为其他对象提供一种代理以控制这个对象的访问。 适用性&#xff1a; l 远程代理&#xff08; Remote Proxy &#xff09;&#xff1a; 为一个对象在不同的地址空间提供局部代表。 l 虚代理&#xff08;Virtual Proxy&#xff09;根据需要创建…

史上最强数学科普!

全世界只有3.14 % 的人关注了爆炸吧知识“中国现代数学之父”华罗庚曾说过宇宙之大&#xff0c;粒子之微火箭之速&#xff0c;化工之巧地球之变&#xff0c;生物之谜日用之繁&#xff0c;无处不用数学回首往昔数学始终伴随我们左右纵横交错的几何、繁琐复杂的运算难以求解的方程…

FastCgi与PHP-fpm之间的关系

我在网上查fastcgi与php-fpm的关系&#xff0c;查了快一周了&#xff0c;基本看了个遍&#xff0c;真是众说纷纭&#xff0c;没一个权威性的定义。网上有的说&#xff0c;fastcgi是一个协议&#xff0c;php-fpm实现了这个协议&#xff1b; 有的说&#xff0c;php-fpm是fastcgi进…

QQ在线联系代码

添加图文模块,标题地址:tencent://message/?uin你的QQ号&Sitemyqq&Menuyes “你的QQ号”就写您自己的Q号 图片地址写:http://wpa.qq.com/pa?p1:你的QQ号:13 “你的QQ号”改为您自己的。“13”为图片样式的序号&#xff0c;可以为1-17。 样式1&#xff1a;样式2&#…

服务器 不支持gbk,解决JS请求服务器gbk文件乱码的问题

JS获取服务器编码格式为gb2312的文件时内容为乱码&#xff0c;ajax网络请求内部使用的是XMLHttpRequest&#xff0c;所以在请求之前需要设置一下编码格式&#xff0c;但是设置xhr.setRequestHeader("accept", "text/csv;charsetgb2312,*/*");没有效果&…

C# 死锁的原理与排查方法详解

01—死锁的原理线程死锁是指由于两个或者多个线程互相持有对方所需要的资源&#xff0c;并且互相等待对方释放资源&#xff0c;导致这些线程都处于等待状态&#xff0c;无法继续执行。如果线程都不主动释放所占有的资源&#xff0c;将产生死锁。如果死锁发生在UI线程&#xff0…

Android之category

CATEGORY_ALTERNATIVE设置这个activity是否可以被认为是用户正在浏览的数据的一个可选择的actionCATEGORY_APP_BROWSER和ACTION_MAIN一起使用&#xff0c;用来启动浏览器应用程序CATEGORY_APP_CALCULATOR和ACTION_MAIN一起使用&#xff0c;用来启动计算器应用程序CATEGORY_APP_…

人生没有对与错,只是选择不同

全世界只有3.14 % 的人关注了爆炸吧知识你用碎片时间学习、赚钱、与时俱进&#xff0c;还是拿来聊天&#xff0c;消遣&#xff0c;刷视频&#xff1f;碎片时间&#xff0c;拉开人生差距&#xff0c;没有对与错&#xff0c;只是选择不同。人生很多地方都有岔路口&#xff0c;很多…

application/x-www-form-urlencoded 与multipart/form-data

为什么上传文件的表单里要加个属性 enctype 上传文件的表单中<form>要加属性enctype"multipart/form-data",很多人只是死记硬背知道上传表单要这么写&#xff0c;知其然而不知其所以然。那到底为什么要添加这个属性呢&#xff1f;它是什么意思呢&#xff1f;它…

学会这些, 让你的服务器远离***影响

介绍:SSH又称Secure Shell, 是linux下常用的远程登陆服务器方式, 其基于SSL加密功能, 相比较ftp, telnet等明文传输协议来说安全等级更高, 在在企业开发环境中被大量使用, 而基于SSH的安全方式鱼龙混杂, 各有春秋. 原因&#xff1a;有一个朋友是做游戏的&#xff0c;他告诉我他…

Android之ActivityManager与Proxy模式的运用

二 Android中ActivityManager 从官方文档的介绍可以看到ActivityManager的作用&#xff1a; 是与系统所有正在运行着的Acitivity进行交互&#xff0c;对系统所有运行中的Activity相关信息&#xff08;Task&#xff0c;Memory&#xff0c;Service&#xff0c;App&#xff09; 进…

服务器文件每天备份重新命名,定时备份服务器文件至本地电脑

你有么有遇到过以下情况&#xff1a;1 写的脚本忘记保存&#xff0c;然后苦逼地再写一遍2 脚本不小心或者小心地删掉了&#xff0c;但后来又发现很有用&#xff0c;依然苦逼地再写一遍3 实验室的服务器炸了&#xff0c;写的脚本全没了一般情况下&#xff0c;第三种情况不会遇到…

河流Shader

原地址&#xff1a;http://www.unity蛮牛.com/blog-2321-336.html Shader "Custom/TextureEffect" {Properties { _MainTint("Diffuse Tint",Color) (1,1,1,1)_MainTex ("Base (RGB)", 2D) "white" {}_ScrollXSpeed("X Scrol…

化学到底有多难难难难!为了让学生搞懂化学,竟然...

▲ 点击查看提到化学&#xff0c;大家脑子里都会想到什么呢&#xff1f;枯燥的化学式&#xff1f;还是难背的元素周期表&#xff1f;还是让人头疼的化学考试题&#xff1f;在由NHK&#xff0c;NHK Educational Corp、西南德国广播&#xff08;SWR&#xff09;、卡塔尔半岛电视台…

面试题--特别是字节对齐

来源&#xff1a;http://www.cnblogs.com/Braveliu/archive/2013/01/04/2844757.html 【1】设置或者清除某位。 示例代码如下: 1 #include<iostream>2 using namespace std;3 4 #define BIT3 (0x1<<3)5 6 void Set_bit3(int &a)7 {8 a|BIT3;9 } 10 11…

配置基于python的VIM环境

配置基于python的VIM环境 安装插件管理工具 为防止过多插件管理的麻烦&#xff0c;首先安装vim的插件管理工具Vundle。vundle本身的github软件已经有相关的中文文档&#xff0c;地址如下&#xff1a; vundle官方中文文档 复制其配置&#xff0c; set nocompatible …