方法内部的私有变量,不存在线程安全问题,永远都是线程安全的,这是方法内部的变量是私有的特性造成的。

实例变量非线程安全,多个线程访问同一个对象的实例变量,则有可能出现非线程安全问题。

synchronized取得的是对象锁,而不是把一段代码或者一个方法当做锁。

调用synchronized的方法一定是排队运行的

A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法

A线程先持有object对象的lock锁,B线程如果在这时调用object对象中的synchronized类型的方法,则需要等待,也就是同步。

一个对象的多个synchronized方法有唯一的对象锁

增加了synchronized的方法一定是同步执行的,例如对象A执行完后synchronized方法后,才可执行对象A的其他synchronized方法。或者说在执行一个对象中的synchronized方法时,必须等待该方法执行完毕。

synchronized锁可重入:对象A的synchronized方法可以调用A对象中的其他synchronized方法。

锁重入也适用于父子类关系的synchronized方法调用

synchronized出现异常时,会自动释放锁

synchronized同步不具有继承性,因此对象A不能继承父类的synchronized方法

同一个对象中的不同synchronized代码块,使用的是同一个锁。

同一个对象中的synchronized代码块与synchronized方法使用的是同一个锁

synchronized代码块参数可以使用非this参数,即可以使用对象的变量或者方法的参数(变量必须是对象的变量,不能是方法内的局部变量)

同一个对象中方法A的synchronized方法与方法B的(非this参数)synchronized代码块线程是非安全的

synchronized加在static静态方法上时,是对类进行加锁,而synchronized加载非static方法上时,是给对象上锁

synchronized代码块中参数为非this参数时,如果一个对象中的有两个方法中各自有一个代码块并且参数不为this,则这两个方法执行时为异步方式,即两个线程调用两个方法时,两个方法同时执行。

volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。

使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile关键字不支持原子性。

关键字volatile是线程同步的轻量级实现,所有volatile性能肯定比synchronized要好,并且volatile只修饰变量,而synchronized可以修饰方法、代码块。

多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。

volatile能保证数据的可见性,但不能保证原子性了,而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。

volatile关键字用于解决变量在多线程之间的可见性。

synchronized关键字解决的事多线程之间访问资源的同步性。

关键字synchronized可以使多个线程访问同一个资源具有同步性,而且他还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能。

sleep与yield是Thread的方法

wait与notify是object类的方法

wait释放锁,notify锁不释放

notify操作会试图唤醒一个因调用wait操作而除去阻塞状态中的线程,如果没有处于阻塞状态的线程,则该命令会被忽略。

wait方法会使调用该方法的线程释放共享资源所,然后从运行状态退出,进入等待队列,直到被再次唤醒。

wait与notify必须在synchronized同步方法或者同步块中调用,如果调用notify与wait是没有持有锁,则报错,notify方法执行后,当前线程不会马上释放该对象 锁,同时wait状态的线程也不能马上获得对象的锁,要等到notify方法的线程执行完后,才会释放对象锁。

每个锁对象有两个队列,一个是就绪队列(存储将要获得锁的线程),一个是阻塞队列(存储被阻塞的线程),wait与notify可以是线程在就绪队列与阻塞队列之间转换。

通过通道进行线程间的通讯:字节流,调用完毕后,需要执行close关闭方法。

PipeInputStream、PipeOutStream

PipeWrite、PipeRead

方法join的作用是等待线程对象销毁。

在调用join的过程中,如果当前线程对象中断了,则当前线程出现异常。

join方法在内部使用了wait方法进行等待,而synchronized关键字使用的是"对象监视器"原理做的他同步。

方法join可以使所属的线程对象X正常执行run方法中的任务,而使当前线程x进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。

join(Long)设定等待时间

join与sleep区别:join方法内部使用了wait方法来实现,所有join方法具有释放锁的特定。而Thread.sleep()方法不能释放锁。

ThreadLocal:主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存储数据的盒子,盒子中可以存储每个线程的私有数据。

多个线程中各自线程设置的ThreadLocal变量是独立的。

InheritableThreadLocal可以在子线程中获得父线程中设置的InheritableThreadLocal值。

如果需要在子线程中对父线程中获得的值就行修改,可以继承InheritableThreadLocal类,同时在childValue方法对父类中获得的值进行修改。

但是需要注意的是,如果子线在获取父类InheritableThreadLocal值得时候,父线程对值进行了更改,那么子线程获取的InheritableThreadLocal值还是旧值。

ReentrantLock

调用ReentrantLock对象的lock()方法获得锁,调用unlock方法释放锁。

lock方法的线程持有的是“对象监视器”

ReentrantLock使用Condition实现等待与通知。

synchronized的线程执行notifyAll时,需要通知所有waiting的线程。没有选择权,会出现相当大的效率问题。

Condition对象调用await()方法之前,必须执行ReentrantLock对象的lock方法,否则会报错。(即必须获得“同步监视器”后才可以执行await方法)

Condition类的signal与await相对应。类似于Object类的wait与notify。

如果一个ReentrantLock类获得多个Condition对象,可以根据Condition不同等待或者唤醒指定的Condition对象。

公平锁与非公平锁

锁Lock 分为公平锁与非公平锁。公平锁便是线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序,而非公平锁就是一种获取锁的抢占机制,是随机获取锁的,和公平锁不一样的是就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平了。

ReentrantLock通过构造参数设置公平锁与非公平锁,默认为公平锁,而ReentrantLock(false)为非公平锁。

ReentrantLock类的getHoldCount方法作用是查看当前线程保持次锁定的个数,也就是调用lock方法的次数(针对于lock嵌套即A方法中有lock方法,同时A方法调用了B方法,同时B方法中也调用了lock的方法,在A方法中getHoldCount返回1,在B方法中getHoldCount返回2)

ReentrantLock类的getQueueLength方法作用是返回正等待获取此锁的线程计数器。

ReentrantLock类的getWaitQueueLength(Condition condition)的作用是返回等待与此锁相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个Condition对象的await方法,则调用getWaitQueueLength方法时返回int值为5.

hasQueueThread作用是查询指定的线程是否正在等待获取此锁定。

hasQueueThreads作用是查询是否有线程正在等待获取此锁定。

hasWaiters作用是查询是否有线程正在等待与此锁有关的Condition条件。

isFair()判断是否是公平锁

isHeldByCurrentThread()查看当前线程是否保持此锁定。

isLocked作用是查询此锁定是否有任意线程保持。

void lockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断(即线程调用了interrupt方法)则返回异常。

boolean tryLock()方法作用是仅在调用时锁定未被另一个线程保持的情况下,才获得该锁定。

awaitUntil(Calendar.getTime())作用是等待到达指定时间,在开始执行之后的代码,该方法可以被notify或者notifyAll唤醒,即未到达指定时间也可以获得锁,继续执行后续代码。

ReentrantReadWriteLock类的多个读线程可以共享锁,但是只要多个线程中有一个写线程,则所有线程就是互斥锁。

Timer定时器

public classTest {public static class TaskService extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("开始运行"+System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

Timer timer = newTimer();

SimpleDateFormat simpleDateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskService taskService= newTaskService();

timer.schedule(taskService,simpleDateFormat.parse("2017-02-27 22:13:10"));

}

}

计划运行时间早于当前时间,则立即执行Task任务。

TimerTask是以队列的方式一个一个被顺序执行的,所以执行的时间有可能和预期的时间不一致,因为前面的任务有可能消耗的时间比较长,则后面的任务运行的时间也会被延期。

schedule(TimerTask task,Date firstTime,long period)方法的作用是在指定日期后,按指定的时间间隔周期性的无限循环地执行某一任务。 period参数为间隔时间(毫秒)

TimerTask类的cancel方法作用是将自身从任务队列中清除。其他任务不受影响。

public classTest {public static class TaskServiceA extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("A开始运行"+System.currentTimeMillis());this.cancel();

}

}public static class TaskServiceB extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("B开始运行"+System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

Timer timer = newTimer();

SimpleDateFormat simpleDateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskServiceA taskServiceA= newTaskServiceA();

timer.schedule(taskServiceA,simpleDateFormat.parse("2017-02-27 22:13:10"),1000);

TaskServiceB taskServiceB= newTaskServiceB();

timer.schedule(taskServiceB,simpleDateFormat.parse("2017-02-27 22:13:10"),1000);

}

}

A开始运行1488209066938

B开始运行1488209066939

B开始运行1488209067939

B开始运行1488209068965

B开始运行1488209069965

B开始运行1488209070965

.....

Timer类的cance方法作用是将任务队列中的全部任务清空。

public classTest {public static Timer timer = newTimer();public static class TaskServiceA extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("A开始运行"+System.currentTimeMillis());

timer.cancel();

}

}public static class TaskServiceB extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("B开始运行" +System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskServiceA taskServiceA= newTaskServiceA();

timer.schedule(taskServiceA,simpleDateFormat.parse("2017-02-27 22:13:10"),1000);

TaskServiceB taskServiceB= newTaskServiceB();

timer.schedule(taskServiceB,simpleDateFormat.parse("2017-02-27 22:13:10"),1000);

}

}

A开始运行1488209178347

Timer类的cance方法作用是将任务队列中的全部任务清空,但是有时候并不一定会停止执行计划任务,而是继续正常执行任务,原因是Timer的cancel方法并没有获得queue锁。

源码:

public voidcancel() {synchronized(queue) {

thread.newTasksMayBeScheduled= false;

queue.clear();

queue.notify();//In case queue was already empty.

}

}

schedule(TimerTask task,long delay)方法的作用是在当前的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次TimerTask任务。

方法schedule与scheduleAtFixRate方法都是按顺序执行的,不需要考虑非线程安全问题

方法schedule与scheduleAtFixRate方法主要区别只在于不延时的情况。

方法schedule如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的开始时间来计算。

scheduleAtFixRate方法如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的结束时间来计算。

Thread.sleep()方法执行后,进入TIMED_WAITING状态

BLOCKED阻塞状态出现在某一个线程在等待锁的时候。

WAITING状态是Object.wait()方法后所处的状态

java多线程核心技术_Java多线程编程核心技术(笔记)相关推荐

  1. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  2. java 高效的多线程同步_java多线程的同步和异步

    java多线程的同步和异步 Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算 ...

  3. java线程 教程_Java多线程系列教程

    Java多线程系列教程 多线程是Java中不可避免的一个重要主体.从本章开始,我们将展开对多线程的学习.接下来的内容是对Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), n ...

  4. java 多线程 总结_Java 多线程总结

    昨天熬了个通宵,看了一晚上的视频,把java 的多线程相关技术重新复习了一遍,下面对学习过程中遇到的知识点进行下总结. 首先我们先来了解一下进程.线程.并发执行的概念: 进程是指:一个内存中运行的应用 ...

  5. java线程入门_java多线程快速入门(一)

    1.什么是进程 比如:QQ.QQ游戏.eclipse都是进程,可以通过任务管理器查看进程 2.进程和线程区别 线程是进程的一部分,一个进程可以包含多个线程,一个线程只能属于一个进程 进程是所有线程的集 ...

  6. java的多线程机制_Java多线程开发(一)| 基本的线程机制

    0. 前言 Java 为了实现跨平台,在语言层面上实现了多线程.我们只需要熟悉 Java 这一套多线程机制就行了,比 C/C++ 要容易多了. 1. 定义任务 我们编写程序,最终是为了完成特定的任务. ...

  7. java线程状态_java并发编程之线程状态

    java线程中,线程状态是如何转换的呢?这一次我们一起来学习下. 线程状态: NEW: 线程创建之后,还没有启动.这时候它的状态就是NEW RUNNABLE: 正在Java虚拟机下跑任务的线程的状态. ...

  8. java并发排它锁_Java并发编程进阶——锁(解析)

    一.锁是什么 java开发中进行并发编程时针对操作同一块区域时,如果不加锁会出现并发问题,数据不是自己预计得到的值.我觉得有点像mysql事务中脏读.不可重复读.幻读的问题.加锁的目的是为了保证同一时 ...

  9. java多线程核心技术_java多线程编程核心技术——第一章总结

    目录: 进程的概念: 百度百科讲解: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 在早期面向进程设计的计算机结构中 ...

最新文章

  1. 宁愿“大小周”、每天只写 200 行代码、月薪 8k-17k 人群再涨!揭晓中国开发者真实现状...
  2. 中科创星投资云游九州,布局时空大数据
  3. 织梦Cms二次开发出来的模块的导出成xml问题
  4. 数据库系统为什么使用三级模式结构
  5. 无惧秋招,您的NLP算法工程师魔鬼训练计划请查收
  6. RocketMQ高性能通信实现机制源码精读
  7. NGINX api网关(mark 有空填坑)
  8. 车联网相关知识点整理
  9. ubuntu18安装wine QQ——2021.11.9
  10. mac系统下用wineskin安装plsql developer及数据乱码解决办法
  11. MySQL数据库安装手册
  12. Unity-创建一个小地图
  13. android 打印kernel log,Android native log输出为kernel log方法
  14. 单反相机的传奇—佳能单反50年辉煌之路(连载十八)
  15. fir.im Weekly - 如何打造 Github 「爆款」开源项目
  16. Java学习:创建简单的名片管理系统
  17. VRT系统常用命令总结
  18. 航天集团研发4000公里/小时高铁是一次战略考量
  19. 【C语言】C语言成长之路之关于C语言的操作符以及一些表达式的讲解(՞• •՞).
  20. elementUI的el-table的树形结构

热门文章

  1. 一种二值图像封闭孔洞的高效填充算法
  2. win10 蓝牙调试工具 Bluetooth LE Explorer 简单使用
  3. Frontline软件CPAS
  4. mybatisplus-性能分析插件
  5. python 实战之模仿开发QQ聊天软件(三)TCP/IP服务器与客户端建设
  6. 190321 逆向-花指令去除(脚本)
  7. webgis —— 为瓦片构建缓存
  8. web前端常用长度单位(px,em,rem,pt)
  9. 已知弧长和弦长求半径
  10. 融合正余弦和柯西变异的麻雀搜索算法