一.对线程的理解

  1.线程概念

    线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

  2.线程的创建方式

    1、继承java.lang.Thread类,并且重写它的run()方法,将线程的执行主体放在其中;

    2、实现java.lang.Runnable接口,实现它的run()方法,并将线程的执行主体放在其中;

    3、实现Callable接口,并实现它的call()方法实现多线程(JDK1.5)

    (由于Java中类是单继承的,所以当类继承一个类时,就无法使用方式一了,开发中方式二更常用)

  3.线程的状态

    

  4.线程的同步

    线程同步方式一(synchronized关键字)

      可以同步方法,也可以同步代码块;对于同步方法来说,每个方法只有获取到所属类实例的锁才可以被执行,一旦该方法被执行,则独占锁,知道方法返回时或者异常退出时才会释放掉锁;同步代码块也是一样,当两个并发线程访问同一个对象中的这个synchronized(this)代码块的时候,一个时间内只有一个线程得到执行,另一个线程只有在这个线程执行完成之后才可以执行;

    线程同步方式一(Lock机制)

      Lock是一个接口,它是jdk1.5新增的,实现Lock接口类具有与synchronized关键字相同的功能,但功能更加强大java.utils.concurrent.locks.ReentrantLock是比较常用的;注意需要在finally中unlock释放锁;

    线程阻塞

      sleep()方法、yield()方法、wait()和join()等方法都可以使线程进入阻塞状态;但是yield方法和wait方法都会释放锁(cpu运行时间),而sleep方法不会释放锁。

  5.线程与进程

     进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP(多核处理机)机器上运行,而进程则可以跨机器迁移。

二.对多线程的理解

  为什么要有多线程

    多线程的出现是为了提高程序的运行效率。(但并不代表多线程的程序运行效率一定高)

  多线程调度

    线程可以完成一定的任务,可以与其他线程共享父进程中的共享变量及部分环境,相互之间协同来完成进程所要完成的任务。线程是独立运行的,它并不知道进程中是否还有其他线程存在,线程的执行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行。

  多线程的安全问题

    多个线程在抢占执行时可能会发生安全问题 (死锁,活锁,饿锁)

      1.死锁应该是最糟糕的一种情况了,它表示两个或者两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

      2.活锁则是类似于: 线程A和B都需要过桥(都需要使用某个资源),而都礼让不走,就这么僵持下去的情况.

      3.饿锁则类似于: 线程A想要某个资源,但后面不停的有线程拿走那个资源,从而A一直拿不到那个资源的情况

  多线程产生死锁的必要条件

  1. 互斥条件:一个资源每次只能被一个线程使用

  2. 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放

  3. 不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺

  4. 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系

  死锁案例

package test;
public class DeadLock{
private static Object o1 = new Object(), o2 = new Object();//用作锁的两个对象
public static void main(String[] args)
{
new Thread(() -> {//lambda表达式
System.out.println("线程1开始执行");
synchronized (o1){
try{
System.out.println("线程1拿到o1锁");
Thread.sleep(1000);//线程休眠,让第二个线程有机会执行
}catch(Exception e){
e.printStackTrace();
}
synchronized (o2){
System.out.println("线程1拿到o2锁执行完毕");
}
}
}).start();
new Thread(() -> {
System.out.println("线程2开始执行");
synchronized (o2){
try{
System.out.println("线程2拿到o2锁");
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
synchronized (o1){
System.out.println("线程2拿到o1锁执行完毕");
}
}
}).start(); }
}

    这两个线程形成死锁,谁都无法执行完毕。

  避免死锁的方式

    1.指定线程的执行顺序,例如,设置一个变量,每次一个执行线程完毕后变量值+1,执行下一个线程前判断变量的值。

    2.“银行家”算法(资源数量 >= 线程数量*(每个线程需要的资源数量-1) + 1  时,不会出现死锁)

    3.死锁检测:当一个线程获取锁的时候,会在相应的数据结构中记录下来,相同下,如果有线程请求锁,也会在相应的结构中记录下来。当一个线程请求失败时,需要遍历一下这个数据结构检查是否有死锁产生。例如:线程A请求锁住一个方法1,但是现在这个方法是线程B所有的,这时候线程A可以检查一下线程B是否已经请求了线程A当前所持有的锁,像是一个环,线程A拥有锁1,请求锁2,线程B拥有锁2,请求锁1。 当遍历这个存储结构的时候,如果发现了死锁,一个可行的办法就是释放所有的锁,回退,并且等待一段时间后再次尝试。

三.线程池的理解

  线程池出现的原因

    线程的频繁创建和销毁是很影响性能的一件事情。而使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。同时,根据系统的承受能力,调整线程池中工作线程的数量,防止浪费内存。

  线程池类

    java.util.concurrent.ThreadPoolExecutor 类就是一个线程池。客户端调用 ThreadPoolExecutor.submit(Runnable task) 提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:

    当前线程池大小 :表示线程池中实际工作者线程的数量;

    最大线程池大小 (maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限;

    核心线程大小 (corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限。(如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;如果运行的线程等于或者多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不是添加新线程;如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超出 maxinumPoolSize, 在这种情况下,任务将被拒绝)

  线程池的使用

    1.创建线程池

ThreadPoolExecutor pool = new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler);//参数根据情况设置

    2.使用线程池中的线程

pool.execute(new Runnable(){
@override
public void run(){
//code
}
});

【Java】 Java多线程(一)的更多相关文章

  1. Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  2. java之多线程 二

    线程的生命周期: 当线程被创建并被启动时,它既不是一启动就进入了执行状态,在线程的生命周期中,它要经过new(新建),就绪(Runnable),运行(Running),阻塞(Blocked),dead ...

  3. Java的多线程机制系列:(一)总述及基础概念

    前言 这一系列多线程的文章,一方面是个人对Java现有的多线程机制的学习和记录,另一方面是希望能给不熟悉Java多线程机制.或有一定基础但理解还不够深的读者一个比较全面的介绍,旨在使读者对Java的多 ...

  4. Java Thread 多线程 介绍

    1.线程概述 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程. 当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程. 2.线程 ...

  5. Java:多线程<一>

    程序运行时,其实是CPU在执行程序的进程,为了提高工作效率一个进程可以有多个线程. Java的多线程: 其实我们之前就见过Java的线程,main就是Java的一个线程,还有另一个条线程总是和main ...

  6. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  7. Java的多线程机制系列:(三)synchronized的同步原理

    synchronized关键字是JDK5之实现锁(包括互斥性和可见性)的唯一途径(volatile关键字能保证可见性,但不能保证互斥性,详细参见后文关于vloatile的详述章节),其在字节码上编译为 ...

  8. Java基础——多线程

    Java中多线程的应用是非常多的,我们在Java中又该如何去创建线程呢? http://www.jianshu.com/p/40d4c7aebd66 一.常用的有三种方法来创建多线程 新建一个类继承自 ...

  9. JAVA之多线程的创建

    转载请注明源出处:http://www.cnblogs.com/lighten/p/5967853.html 1.概念 老调重弹,学习线程的时候总会牵扯到进程的概念,会对二者做一个区分.网上有较多的解 ...

  10. Java基础--多线程的方方面面

    1,什么是线程?线程和进程的区别是什么? 2,什么是多线程?为什么设计多线程? 3,Java种多线程的实现方式是什么?有什么区别? 4,线程的状态控制有哪些方法? 5,线程安全.死锁和生产者--消费者 ...

随机推荐

  1. python3笔记六:for语句

    一:学习内容 for语句 二:for-in语句 1. 格式 for 变量名 in 集合:    语句 2.逻辑 按顺序取集合中的每个元素赋值给变量,再去执行语句,如此循环往复 3.举例 for i i ...

  2. linux设置MySQL开机自动启动

    step1: 通过chkconfig --list命令查看mysqld是否在列表中: step2: 如果列表中没有mysqld这个,需要先用这个命令添加:chkconfig --add mysqld ...

  3. 构建基于Electron开发的软件遇到的问题

    构建pdman时,报了好些错. 主要还是网络问题和版本不一致导致的. 前提 npm设置淘宝源,自行搜索. 版本 上面是官方要求的node环境. 需要首先安装nvm, brew install nvm ...

  4. Centos 6.5 Multipath 初始配置

    # This is a basic configuration file with some examples, for device mapper # multipath. # For a comp ...

  5. Kotlin 的函数定义和使用 (译文 转)

    Kotlin 的函数定义和使用 函数声明Kotlin 中的函数使用 fun 关键字声明 fun double(x: Int): Int {}函数用法调用函数使用传统的方法 val result = d ...

  6. Oracle中如何生成随机数字、随机字符串、随机日期

    .随机小数 dbms_random.value(low,high): --获取一个[low,high)之间的小数,包含low,不包含high 可以结合trunc函数获取整数 例如: select db ...

  7. 我非要捅穿这 Neutron(一)网络实现模型篇

    目录 文章目录 目录 前言 传统网络到虚拟化网络的演进 单一平面网络到混合平面网络的演进 Neutron 简述 Neutron 的网络实现模型 计算节点网络实现模型 内外 VID 转换 网络节点网络实 ...

  8. vim 编辑提示swap file already exists 解决方法

    linux服务器上编辑 .ini 文件时卡死,关闭连接工具后重新进入操作该 .ini 文件时,会提示: E325: ATTENTION Found a swap file by the name &q ...

  9. 解决kubeadm部署kubernetes集群镜像问题

    kubeadm 是kubernetes 的集群安装工具,能够快速安装kubernetes 集群.kubeadm init 命令默认使用的docker镜像仓库为k8s.gcr.io,国内无法直接访问,需 ...

  10. MyBatis框架原理1:构建SqlSessionFactory的过程

    SqlSessionFactoryBuilder 首先创建了一个SqlSessionFactoryBuilder对象,然后调用该对象的build方法加载全局XML配置的流文件构建出一个SqlSessi ...