JAVA学习总结-多线程基础:

参考书籍:疯狂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()来获得子线程执行结束后的返回值.

3.线程的生命周期;

 

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();来关闭线程池.

 

原文地址:https://www.cnblogs.com/Kingram/p/8947766.html

时间: 2024-08-25 10:14:37

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

JAVA学习篇--JSTL基础

JSTL是什么 JSTL(JSP Standard TagLibrary,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库. 为什么要用JSTL 我们JSP用于开发信息展现页非常方便;也可以嵌入java代码(scriptlet.表达式和声明)代码用来实现相关逻辑控制.看下面程序.但这样做会带来如下问题: jsp维护难度增加;出错提示不明确,不容易调试; 分工不明确;(即jsp开发者是美工,也是程序员); 最终增加程序的开发成本; <% if (session.getAttribute(

JAVA学习笔记 -- 多线程之共享资源

在多线程程序运行过程中,可能会涉及到两个或者多个线程试图同时访问同一个资源.为了防止这种情况的发生,必须在线程使用共享资源时给资源"上锁",以阻挡其它线程的访问.而这种机制也常常被称为互斥量,本文主要介绍它的两种方式synchronized和Lock . 1.synchronized 当任务要执行被synchronized关键字保护的代码片段的时候,它会检查锁是否可用,然后获取锁,执行代码,释放锁.synchronized也有两种用法: A.synchronized方法 import

JAVA学习_零基础学习JAVA方法_零基础学习JAVA思路

在学习JAVA前,对于一个真正初学者(也就是从零开始学习JAVA人员)的一个问题:什么是JAVA,然后才是怎么学习JAVA?JAVA是sun microsystems在1995年推出的高级编程语言,其分为Java SE.Java EE.Java ME三大体系,而JAVA SE是JAVA的基础,继JAVASE之后是JAVAEE,JAVA ME.JAVASE是JAVAEE的基础,Servlet.JSP是框架的基础.数据库方面个人建议学习oracle,当然其它的像 MySQL,MSSQL,都可以,只要

Java学习笔记—多线程(java.util.concurrent并发包概括,转载)

一.描述线程的类:Runable和Thread都属于java.lang包 二.内置锁synchronized属于jvm关键字,内置条件队列操作接口Object.wait()/notify()/notifyAll()属于java.lang包 二.提供内存可见性和防止指令重排的volatile属于jvm关键字 四.而java.util.concurrent包(J.U.C)中包含的是java并发编程中有用的一些工具类,包括几个部分: 1.locks部分:包含在java.util.concurrent.

Java学习的一些基础笔记

classpath.;%java_home%\lib;%java_home%\lib\tools.jar;D:\Java\;java_homeD:\Program Files\Java\jdk1.8.0_51pathC:\Users\BaseKing-Sunie\AppData\Local\Code\bin;%java_home%\bin;%java_home%\jre\bin;D:\adt-bundle-windows-x86_64_20131020\sdk\tools;D:\adt-bund

#Java学习之路——基础阶段二(第五篇)

我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言:此随笔主要是Java基础中的基础,相信大家对这方面肯定有着自己的理解和认识,具体详解可以参照万能的baidu,有的我就一笔带过,希望在我的学习之路上能够有大牛进行指导,也有更多的小伙伴共勉. 1.异常 异常在我们平时编译的时候会有两种情况,一种是编译报错,一种是运行报错,还有一种较为严重的就是直接e

#Java学习之路——基础阶段二(第九篇)

我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言:此随笔主要是Java基础中的基础,相信大家对这方面肯定有着自己的理解和认识,具体详解可以参照万能的baidu,有的我就一笔带过,希望在我的学习之路上能够有大牛进行指导,也有更多的小伙伴共勉. 1.网络编程入门 首先要了解软件的结构有两种一种是C/S全称是Client/server 客户端和服务器之间

java学习笔记 多线程

进程是程序的一次动态执行过程,需要经历代码加载,代码执行,执行完毕的一个完整过程. 多进程操作系统能同时运行多个进程(程序),由于cpu具有备份时机制,所以每个进程都能循环获得自己的cpu时间片.由于cpu执行速度非常快,使得所有程序好像是在"同时运行"一样. 线程是比进程更小的单位,线程是在进程基础上进一步的划分.多线程是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的程序单元称之为线程.(java在运行中至少会启动两个线程:1,main线程 2,垃圾回收线程) 线程的实

Java学习笔记---多线程同步的五种方法

一.引言 前几天面试,被大师虐残了,好多基础知识必须得重新拿起来啊.闲话不多说,进入正题. 二.为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常.举个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块.假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚.因此多线程同步就