参考书籍:疯狂JAVA讲义

1.进程和线程;

进程是处于运行过程中的程序;并且具有一定的独立功能;进程是系统进行系统资源分配和调度的一个独立单位.

一般而言,进程包括以下三个特征:

独立性:进程是系统中存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间.在没有经过进程本身允许的情况下,一个用户进程不可以访问其他进程的地址空间.

动态性:进程与程序的区别在于,程序是一个静态的指令集合,而进程是一个正在系统中活动的指令集合.在进程中加入了时间的概念,进程具有自己的生命周期和不同的状态,这些概念都是程序不具备的.

并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响.

什么是并发?

并发指的是同一时刻只有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果.

线程是进程的执行单元,当进程被初始化后,主线程就创建了.

 

操作系统可以同时执行多个任务,每一个任务就是一个进程,进程可以同时执行多个任务,每个任务就是线程.

2.线程的创建和启动;

JAVA使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.

2.1,继承Thread创建线程类

--定义Thread的子类,并重写run();该方法的方法体就代表了线程需要完成的任务,因此把run()称为线程执行体.

--创建该类的实例,即创建了线程对象.

--调用线程对象的start();启动线程.

 

2.2,实现Runnable接口创建线程类

--定义Runnable接口的实现类,并重写该接口的run();该方法的方法体同样是该线程的线程执行体.

--创建Runnable实现类的实例,并以此作为Thread的参数来创建Thread对象,这个对象才是线程对象.

--调用线程对象的额start();启动线程.

 

2.3,使用Callable和Future创建线程

--创建Callable接口的实现类,并实现call();该call()将作为线程执行体,且该call()有返回值,再创建Callable实现类的实例.

--使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()的返回值.

--使用FutureTask对象作为Thread的参数创建并启动线程.

--调用FutureTask对象的get()来获得子线程执行结束后的返回值.

  1. 线程的生命周期;

 

3.1,新建状态(New):新创建了一个线程对象。

3.2,就绪状态(Runnable):当线程对象调用了start();该线程处于就绪状态;并没有开始运行,只是表明该线程可以运行了,至于什么时候开始运行,取决于JVM里的线程调度器的调度.

注意:这里不能直接调用run();否则系统把线程对象当作普通对象,把run()当成普通方法,而不是线程执行体.

 

3.3,运行状态(Running):就绪状态的线程获取了CPU,执行run()的线程执行体.

3.4,阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权;暂时停止运行。直到线程进入就绪状态.才有机会转到运行状态.阻塞的情况分三种:

(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中;(wait()会释放持有的锁);

(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中;

(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态,当sleep()状态超时,join()等待线程终止或者超时,或者I/O处理完毕时,线程重新转入就绪状态;(注意:sleep()是不会释放持有的锁).

3.5,死亡状态(Dead):run(),call()执行完毕,或抛出未捕获异常,该线程结束生命周期。

/**为了测试某个线程是否死亡,可以调用线程对象的isAlive(),当线程处于,就绪,运行,阻塞状态时返回ture,在新建和死亡状态时返回false*/

4.控制线程;

4.1,守护线程

当程序中只剩下守护线程时,他会自杀;

JVM的垃圾回收线程就是守护线程;

调用Thread的setDaemon(true);可以将指定线程设置成守护线程.

注意:要将某个线程设置成守护线程,必须在该线程启动之前,即start()调用之前.

4.2,线程睡眠

通过调用Thread的static方法sleep()让当前的线程进入暂停一段时间,进入阻塞状态.

4.3,线程让步

yield()方法也是Thread的static方法,他不会使该线程进入阻塞状态,只是转入就绪状态,完全有可能的是:当某个线程调用了yield()暂停之后,线程调度器又将其调度出来重新执行;

注意:只有优先级和当前线程相同或者比当前线程更高的处于就绪状态的线程才会获得执行的机会.

4.4,改变线程优先级

每个线程执行时都有一定的优先级,优先级高的线程获得较多的执行机会,而优先级较低的线程则获得较低的执行机会,;默认情况下main线程具有优先级,由main线程创建的子线程也具有优先级;

Thread类提供了setPriority(int newPriority);getPriority();方法来改变和获取线程的优先级,范围在1-10之间.

4.5,join()线程

Thread提供了一个线程等待另一个线程执行的方法,当在某个程序的执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的线程执行完为止.

Join():等待join线程执行完成

Join(long millis):等待join线程完成时间最多为millis毫秒,如果在millis毫秒内该线程还没有结束,则不再等待.

5.线程同步;

5.1,线程安全问题

这个案例中,你和你老婆相当于俩个并发线程,都在修改存款,系统在判断你的条件满足后正好执行线程切换,切换给你老婆去执行,所以会产生问题.

5.2,同步代码块

为了解决这个问题,java的多线程引入了同步监视器来解决这个问题.

同步监视器的目的:组织2个线程对同一个共享资源进行并发访问.

synchronized(obj) {

//此处的代码就是同步代码块

}

上述obj就是同步监视器,当线程开始执行同步代码块之前,必须获得对同步监视器的锁定.

注意:任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完毕后,该线程会释放对该同步代码块的锁定.

5.3,同步方法

即使用synchronized修饰某个方法(非static修饰),则该方法就是同步方法,无需指定同步监视器,同步方法的同步监视器是this,也就是调用该方法的对象.

5.4,释放同步监视器的锁定

线程在如下情况会释放对同步监视器的锁定:

--当线程的同步方法,同步代码块执行结束,会释放对同步监视器的锁定.

--当前线程在同步代码块,同步方法中出现了break,return终止了该代码块,方法的执行,会释放对同步监视器的锁定.

--当前线程在同步代码块,同步方法中出现了未处理的Exception,Error,导致了该方法,代码块异常结束,会释放同步监视器的锁定.

--当前线程在同步代码块,同步方法中执行了同步监视器对象的wait(),则当前线程暂停,并释放同步监视器的锁定.

在如下所示的情况下,线程不会释放对同步监视器的锁定:

--线程在执行同步代码块,同步方法时,程序调用Thread.sleep();Thread.yield();暂停当前线程的执行,当前线程不会释放同步监视器的锁定.

5.5,死锁

当2个线程互相等待对方释放同步监视器时就会发生死锁.

5.6,线程池

系统启动一个线程池的成本是比较高的,因为它涉及到与操作系统交互,在这种情况下使用线程池可以很好的提高性能.

线程池在系统启动时即创建了大量空闲的线程,程序将一个Runnable对象或者Callable对象传给线程池,线程池就会启动一个线程来执行他们的run();或者call();当方法结束后,线程不会死亡,而是返回线程池中成为空闲状态,等待下一个对象.

使用Executors工厂类来产生线程池,该工厂类包含如下几个静态方法来创建线程池:

Executors.newCachedThreadPool();创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中.

Executors.newFixedThreadPool(int nThreads);创建一个可重用的,具有固定线程数的线程池.

Executors.newSingleThreadExecutor();创建一个只有单线程的线程池,相当于调用newFixedThreadPool(),方法参数传1.

以上三个方法,返回一个ExecutorService对象,该对象代表一个线程池.

Executors.newScheduledThreadPool(int corePoolSize);创建具有指定线程数的线程池,它可以在指定延迟后执行任务,corePoolSize指的是线程池中所保存的线程数.

此方法返回一个ScheduledExecutorService线程池,它是ExecutorService的子类,它可以在指定延迟后执行任务.

使用线程池来执行线程任务的步骤

5.6.1,调用Executor的静态工厂方法创建一个ExecutorService对象,该对象代表一个线程池;

5.6.2,创建Runnable实现类的实例,作为线程执行任务;

5.6.3,调用ExecutorService对象的submit()方法来提交Runnable实例.

5.6.4,当不想提交任何任务时,调用ExeccutorService对象的shutdown();来关闭线程池.

 

JAVA学习总结-多线程基础:的更多相关文章

  1. 2019/3/7 Java学习之多线程(基础)

    Java学习之多线程 讲到线程,就必须要懂得进程,进程是相当于一个程序的开始到结束,而线程是依赖于进程的,没有进程,就没有线程.线程也分主线程和子线程,当在主线程开启子线程时,主线程结束,而子线程还可 ...

  2. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  3. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

  4. Java学习笔记之---基础语法

    Java学习笔记之---基础语法 一. Java中的命名规范 (一)包名 由多个单词组成时,所有字母小写(例如:onetwo) (二)类名和接口 由多个单词组成时,所有单词首字母大写(例如:OneTw ...

  5. Java学习---程序设计_基础题[1]

    180813 补全没有的答案! 0. 数组排序大全[冒泡/选择/快速/插入] package com.ftl; import java.io.BufferedReader; import java.i ...

  6. JAVA学习笔记之基础概念(一)

    一.Java 简介: Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称. 由 James Gosling和同 ...

  7. Java学习1——计算机基础知识

    本文包含了一些计算机基础知识:计算机组成:Windows常用快捷键:DOS常用命令:计算机语言发展史.

  8. Java学习之旅基础知识篇:数据类型及流程控制

    经过开篇对Java运行机制及相关环境搭建,本篇主要讨论Java程序开发的基础知识点,我简单的梳理一下.在讲解数据类型之前,我顺便提及一下Java注释:单行注释.多行注释以及文档注释,这里重点强调文档注 ...

  9. java中的多线程 // 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

随机推荐

  1. 初次面对c++

    第一次实验 2-4源码: #include<iostream> using namespace std; int main() { int day; cin>>day; swi ...

  2. SpringBoot应用的集成测试

    一.概念和定义 进行软件开发的时候,我们会写很多代码,不过,再过六个月(甚至一年以上)你知道自己的代码怎么运作么?通过测试(单元测试.集成测试.接口测试)可以保证系统的可维护性,当我们修改了某些代码时 ...

  3. 阿里云API网关(7)开发指南-API参考

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  4. SpringCloud的服务消费者 (一):(rest+ribbon)访问注册的微服务

    采用Ribbon或Feign方式访问注册到EurekaServer中的微服务.1.Ribbon实现了客户端负载均衡,Feign底层调用Ribbon2.注册在EurekaServer中的微服务api,不 ...

  5. netty学习--handler传递

    在netty中的处理链pipeline中,事件是按顺序传递的,把自己拟人为netty程序,针对进来(inbound)的请求,会从head开始,依次往tail传递. pipeline采用了链表结构,he ...

  6. JavaScript的基础学习

    由js和python想到的: 弱类型语言 js 中的数据在进行算数运算时,会自动转换类型强类型语言 变量的值的数据类型一旦确定,使用时不能改变 动态语言:编译时不知道数据类型,只有在执行时才知道数据类 ...

  7. Java面试题——中级(下)

    内部类和静态内部类的区别 内部类: 1.内部类中的变量和方法不能声明为静态的. 2.内部类实例化:B是A的内部类,实例化B:A.B b = new A().new B(). 3.内部类可以引用外部类的 ...

  8. [python]_ELVE_pip2和pip3如何共存

    作者:匿名用户链接:https://www.zhihu.com/question/21653286/answer/95532074来源:知乎著作权归作者所有,转载请联系作者获得授权. 想学习Pytho ...

  9. 【转载】Linux下安装、配置、启动Apache

    原文地址:http://www.cnblogs.com/zhuque/archive/2012/11/03/2763352.html 安装Apache前准备: 1.检查该环境中是否已经存在httpd服 ...

  10. [LeetCode] Add One Row to Tree 二叉树中增加一行

    Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...