一.对线程的理解

  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. 出现org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER, 且出现无法找到Maven的依赖的问题

    解决方案:Build Path -> Java Build Path ->Libraries ->Add Library ->Maven Managed Dependences ...

  2. IDEA配置常见配置

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  3. 【转】diamond专题(一)– 简介和快速使用

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  4. C与指针学习笔记

    有些任务无法用其他语言实现,如直接访问硬件,但C却可以. C对数组下标引用和指针访问并不进行有效性检查,这可以节省时间,但你在使用这些特性时,就必须特别小心.

  5. spark 笔记 4:Apache Hadoop YARN: Yet Another Resource Negotiator

    spark支持YARN做资源调度器,所以YARN的原理还是应该知道的:http://www.socc2013.org/home/program/a5-vavilapalli.pdf    但总体来说, ...

  6. 一、基础篇--1.1Java基础-Session和Cookie的区别【转】

    https://www.cnblogs.com/zlw-xf/p/8001383.html 1:cookie数据存放在客户的浏览器上(客户端),session数据放 @1:cookie不是很安全,别人 ...

  7. 全面解读php-面向对象

    一.类的自动载入 //类的自动载入我们使用 spl_autoload_register($autoload_function ).我们需要在不同的地方包含更多不同的类文件,只需要多写几个 $autol ...

  8. [转]Tomcat中8005/8009/8080/8443端口的作用

    8005:关闭tomcat进程所用.当执行shutdown.sh关闭tomcat时就是连接8005端口执行“SHUTDOWN”命令--由此,我们直接telnet8005端口执行“SHUTDOWN”(要 ...

  9. matplotlib之折线图

    1.案例一 # coding=utf-8 from matplotlib import pyplot as plt import random # 设置字体相关 from matplotlib imp ...

  10. 一键发布shell脚本

    1.配置集群间免密登录 (1)配置host:vim /etc/hosts (2)生成公钥 :ssh-keygen -t rsa -P '' 这时会提示生成的公钥的存放地址,直接回车,公钥生成成功 (3 ...