卑微小吴励志写博客第三天

多线程

1 什么是线程,线程与进程的关系

线程是程序的执行路径,或者可以说是程序的控制单元。
一个进程可能包含一个或多个线程,当一个进程存在多条执行路径时,就可以将该执行方式称为多线程。
线程的执行方式大致可分为就绪(wait),执行(run),阻塞(block)三个状态,而三个状态的转换实质上是在抢夺cpu资源过程中造成的,正常情况下cpu资源不会被线程独自占用,因此多个线程在运行中相互抢夺资源,造成线程在上述的三个状态之间不断的相互转换。而这也是多线程的执行方式。

2 同步和异步的区别

同步(Sync)
所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。
根据这个定义,Java中所有方法都是同步调用,应为必须要等到结果后才会继续执行。我们在说同步、异步的时候,一般而言是特指那些需要其他端协作或者需要一定时间完成的任务。
简单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事。
异步(Async)
异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。

举个例子简单说明下两者的区别:
同步:火车站多个窗口卖火车票,假设A窗口当卖第288张时,在这个短暂的过程中,其他窗口都不能卖这张票,也不能继续往下卖,必须这张票处理完其他窗口才能继续卖票。直白点说就是当你看见程序里出现synchronized这个关键字,将任务锁起来,当某个线程进来时,不能让其他线程继续进来,那就代表是同步了。

异步:当我们用手机下载某个视频时,我们大多数人都不会一直等着这个视频下载完,而是在下载的过程看看手机里的其他东西,比如用qq或者是微信聊聊天,这种的就是异步,你执行你的,我执行我的,互不干扰。比如上面卖火车票,如果多个窗口之间互不影响,我行我素,A窗口卖到第288张了,B窗口不管A窗口,自己也卖第288张票,那显然会出错了

3 创建线程的三种方式

  • 继承Thread类,重写父类run()方法
public class MyThread extends Thread{@Overridepublic void run() {// TODO Auto-generated method stub//super.run();doSomething();}private void doSomething() {// TODO Auto-generated method stubSystem.out.println("我是一个线程中的方法");}
}
  • 实现runnable接口
public class RunnableThread implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubdoSomeThing();}private void doSomeThing() {// TODO Auto-generated method stubSystem.out.println("我是一个线程方法");}}
  • 使用ExecutorService、Callable、Future实现有返回结果的多线程(JDK5.0以后)
public class CallableThread implements Callable<String>{@Overridepublic String call() throws Exception {// TODO Auto-generated method stubdoSomeThing();return "需要返回的值";}private void doSomeThing() {// TODO Auto-generated method stubSystem.out.println("我是线程中的方法");}}

3.1 采用实现Runnable、Callable接口的方式创建多线程的优缺点。

优势:

  • 线程类只是实现了Runnable接口与Callable接口,还可以继承其他类。
  • 在这种方式下,多个线程可以共享一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

劣势:

  • 编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。

3.2 采用继承Thread类的方法创建多线程的优缺点。

优势:

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

劣势:

  • 因为线程类已经继承了Thread类,所以不能再继承其他父类。

总结:一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程。

4 线程池

4.1 线程池的作用

线程池作用就是限制系统中执行线程的数量。
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程 排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待为什么要用线程池:。当一个新任务需要运行时,如果线程 池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

4.2为什么要用线程池

减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务
器累趴下(每个线程需要大约 1MB 内存,线程开的越多,消耗的内存也就越大,最后死机)

4.3 java中的四种线程池

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

5 多线程同步机制。

  • 在需要同步的方法的方法签名中加入synchronized关键字。
  • 使用synchronized块对需要进行同步的代码段进行同步。
  • 使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。
    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁); 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池 等待队列中)。 取到锁后,他就开始执行同步代码(被synchronized修饰的代码);线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中 等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻只有一个线程在执行。

6 线程的生命周期

线程在执行过程中,可以处于下面几种状态:
就绪(Runnable):线程准备运行,不一定立马就能开始执行。
运行中(Running):进程正在执行线程的代码。
等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
睡眠中(Sleeping):线程被强制睡眠。
I/O阻塞(Blocked on I/O):等待I/O操作完成。
同步阻塞(Blocked on Synchronization):等待获取锁。
死亡(Dead):线程完成了执行。

7 什么是守护线程?

守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这是它的作用——而其他的线程只有一种,那就是用户线程。所以java里线程分2种,
1、守护线程,比如垃圾回收线程,就是最典型的守护线程。

守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了。
再换一种说法,如果有用户自定义线程存在的话,jvm就不会退出——此时,守护线程也不能退出,也就是它还要运行,干嘛呢,就是为了执行垃圾回收的任务啊。

2、用户线程,就是应用程序里的自定义线程。

应用程序里的线程,一般都是用户自定义线程。
用户也可以在应用程序代码自定义守护线程,只需要调用Thread类的设置方法设置一下即可

8 线程锁

多线程可以同时运行多个任务
但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误!
so,不使用线程锁, 可能导致错误。
应用场景:
I/O密集型操作 需要资源保持同步
优缺点:
优点:保证资源同步
缺点:有等待肯定会慢

9 sleep方法和wait方法的区别?

  • 来自不同的类: wait()方法是Object类的方法,sleep方法是Thread类的方法。
  • 对于锁的占用情况不同:最主要是sleep方法没有释放锁,而 wait 方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  • 使用范围: wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用)
  • 唤醒方式:调用sleep()方法的线程通常是睡眠一定时间后,自动醒来。对象调用wait()方法,必须采用notify()或者notifyAll()方法唤醒。

Sleep()方法

Sleep()方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。
注意sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过t.sleep()让t对象进入sleep,这样的做法是错误的,它只会是使当前线程被sleep 而不是t线程。

Wait()方法

Wait()属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生InterruptedException,效果以及处理方式同sleep()方法。

10 什么是死锁(deadlock)?如何避免死锁?

两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。

关于多线程与锁的一些知识,确实很难。每次看到这里都没弄的太懂,不过多看一些关于多线程的知识后还是有一些进步的。希望这篇博客能帮助小伙伴对线程,多线程有一定的了解。

浅谈java中的线程,多线程相关推荐

  1. java 线程 交给spring_浅谈Java中spring 线程异步执行

    多线程并发处理起来通常比较麻烦,如果你使用spring容器来管理业务bean,事情就好办了多了.spring封装了Java的多线程的实现,你只需要关注于并发事物的流程以及一些并发负载量等特性,具体来说 ...

  2. java 线程aba,浅谈Java中ABA问题及避免,浅谈javaaba避免

    浅谈Java中ABA问题及避免,浅谈javaaba避免 本文主要研究的是关于Java中ABA问题及避免的相关内容,具体如下. 在<Java并发实战>一书的第15章中有一个用原子变量实现的并 ...

  3. java中单例的应用_浅谈Java中单例模式的几种应用

    目录 浅谈Java中单例模式的几种应用 第一种:懒汉式 第二种:饿汉式 第三种:双重检索式 第四种:注册登记式 第五种:内部类形式 浅谈Java中单例模式的几种应用 日常开发中,为了提高我们系统中对象 ...

  4. aba会导致问题_浅谈Java中ABA问题及避免

    本文主要研究的是关于Java中ABA问题及避免的相关内容,具体如下. 在<Java并发实战>一书的第15章中有一个用原子变量实现的并发栈,代码如下: public class Node { ...

  5. java 中的单元测试_浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...

  6. 浅谈Java中的Set、List、Map的区别

    就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...

  7. java中修饰常量的事_浅谈java中的声明常量为什么要用static修饰

    今天定义一个类常量,想着也只有这个类可以用到,就没用static关键字修饰.结果sonar代码检查提示: Rename this field "PERSON_TYPE_USER" ...

  8. 浅谈JAVA中如何利用socket进行网络编程(二)

    转自:http://developer.51cto.com/art/201106/268386.htm Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以 ...

  9. scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别

    这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都 ...

最新文章

  1. 图神经网络的解释性综述!
  2. shell 文本后几行_shell_wc(统计数目)、head(查看前几行)、tail(查看末尾几行)...
  3. 解决Ubuntu下pycharm无法输入中文的问题
  4. plsql无监听程序_详细!看看顶级互联网公司都在研究的无服务器架构!
  5. linux DNS安装配置
  6. MongoDB 查询 (转) 仅限于C++开发
  7. 数组作为方法的返回值
  8. python mobilenetssd android_MobileNetV2-SSDLite运行
  9. 一个软件测试员的工作与学习(二)
  10. SLAM无人车通过上摄像头扫描二维码重定位
  11. 如何查看Windows8.1计算机体验指数评分
  12. C语言:编写一个程序,求s=1+(1+2)+(1+2+3)+....+(1+2+3+....+n)的值。
  13. 名企面试官精讲典型编程题之C++篇
  14. 基于java自行车租赁管理系统
  15. 饥荒联机版专用服务器主机性能较差,饥荒联机版为什么启动服务器慢 | 手游网游页游攻略大全...
  16. ddm模型公式_绝对估值法DDM、DCF模型和RNAV简介
  17. 批处理设置计算机不休眠,Windows 定时休眠 睡眠 批处理命令
  18. 华为项目管理金种子培训教材(资料下载)
  19. 计算机科学与技术大学容易挂科吗,大一容易“挂科”的4个学科,学霸都未必敢报,最后一个“团灭”...
  20. emwin添加图标和图片

热门文章

  1. OllyDbg和DTDebug的页面字体设置调整
  2. 基于openSUSE11.0交叉编译嵌入式linux系统产品
  3. 【活动预告】数据集成海外专场Meetup:走进Shopee,聊透SeaTunnel优化实践
  4. 如何证明夫妻已经分居2年?
  5. js 字符串转字节数组,字节数组转字符串(互转)
  6. 阿里将成为下一个谷歌?是谁Google真正的挑战者
  7. SqlServer数据库分离和附加
  8. 毕业设计 基于Arduino的肺活量计
  9. 基于RK3288 平台 Simple card声卡添加及调试
  10. LeetCode 827 最大人工岛 C++