`

线程123总结

 
阅读更多
线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

因此,关于线程同步,需要牢牢记住的第一点是:线程同步就是线程排队。同步就是排队。线程同步的目的就是避免线程“同步”执行。这可真是个无聊的绕口令。
关于线程同步,需要牢牢记住的第二点是 “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。
关于线程同步,需要牢牢记住的第三点是,只有“变量”才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。
关于线程同步,需要牢牢记住的第四点是:多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。

为什么不在每一个对象内部都增加一个新的区域,专门用来加锁呢?这种设计理论上当然也是可行的。问题在于,线程同步的情况并不是很普遍。如果因为这小概率事件,在所有对象内部都开辟一块锁空间,将会带来极大的空间浪费。得不偿失。
于是,现代的编程语言的设计思路都是把同步锁加在代码段上。确切的说,是把同步锁加在“访问共享资源的代码段”上。这一点一定要记住,同步锁是加在代码段上的。

我们应该在代码段上加什么样的锁。这个问题是重点中的重点。这是我们尤其要注意的问题:访问同一份共享资源的不同代码段,应该加上同一个同步锁;如果加的是不同的同步锁,那么根本就起不到同步的作用,没有任何意义。
这就是说,同步锁本身也一定是多个线程之间的共享对象。

在Java里面,同步锁的概念就是这样的。任何一个Object Reference都可以作为同步锁。我们可以把Object Reference理解为对象在内存分配系统中的内存地址。


同一时刻,只有一个线程能够获得lock1的所有权,只有一个线程可以执行代码段A或者代码段B。其他竞争失败的线程只能暂停运行,进入到该同步锁的就绪(Ready)队列。
每一个同步锁下面都挂了几个线程队列,包括就绪(Ready)队列,待召(Waiting)队列等。比如,lock1对应的就绪队列就可以叫做lock1 - ready queue。每个队列里面都可能有多个暂停运行的线程。
注意,竞争同步锁失败的线程进入的是该同步锁的就绪(Ready)队列,而不是后面要讲述的待召队列(Waiting Queue,也可以翻译为等待队列)。就绪队列里面的线程总是时刻准备着竞争同步锁,时刻准备着运行。而待召队列里面的线程则只能一直等待,直到等到某个信号的通知之后,才能够转移到就绪队列中,准备运行。
成功获取同步锁的线程,执行完同步代码段之后,会释放同步锁。该同步锁的就绪队列中的其他线程就继续下一轮同步锁的竞争。成功者就可以继续运行,失败者还是要乖乖地待在就绪队列中。
因此,线程同步是非常耗费资源的一种操作。我们要尽量控制线程同步的代码段范围。同步的代码段范围越小越好。我们用一个名词“同步粒度”来表示同步代码段的范围。

同步锁模型只是最简单的同步模型。同一时刻,只有一个线程能够运行同步代码。
有的时候,我们希望处理更加复杂的同步模型,比如生产者/消费者模型、读写同步模型等。这种情况下,同步锁模型就不够用了。我们需要一个新的模型。这就是我们要讲述的信号量模型。
信号量模型的工作方式如下:线程在运行的过程中,可以主动停下来,等待某个信号量的通知;这时候,该线程就进入到该信号量的待召(Waiting)队列当中;等到通知之后,再继续运行。


原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的。
AtomicLong aLong = new AtomicLong(10000);
aLong.addAndGet(x));
信号量仅仅是对池资源进行监控,但不保证线程的安全,因此,在使用时候,应该自己控制线程的安全访问池资源。
new Semaphore(size)

getSp().acquire(x);
getSp().release(x);


条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。

myLock.lock();
Lock lock = new ReentrantLock();
myLock.unlock();

Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。
ReadWriteLock lock = new ReentrantReadWriteLock(false);
myLock.readLock().lock();
myLock.readLock().unlock();

myLock.writeLock().lock();
myLock.writeLock().unlock();


Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止
Java为阻塞栈定义了接口:java.util.concurrent.BlockingDeque


线程的调度-让步
线程的让步使用Thread.yield()方法,yield() 为静态方法,功能是暂停当前正在执行的线程对象,并执行其他线程。

线程的调度-合并
应用场景是当一个线程必须等待另一个线程执行完毕才能执行时可以使用join方法。
Thread t1 = new MyThread1();
//t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
t1.join();

线程的调度-休眠

线程休眠的目的是使线程让出CPU的最简单的做法之一,线程休眠时候,会将CPU资源交给其他线程,以便能轮换执行,当休眠一定时间后,线程会苏醒,进入准备状态等待执行。

线程的交互

等待/通知,要记住的关键点是:
必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。
wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行。如果没有线程等待,则不采取任何特殊操作。

锁和同步,有一下几个要点:
1)、只能同步方法,而不能同步变量和类;
2)、每个对象只有一个锁;当提到同步时,应该清楚在什么上同步?也就是说,在哪个对象上同步?
3)、不必同步类中所有的方法,类可以同时拥有同步和非同步方法。
4)、如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。
5)、如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制。
6)、线程睡眠时,它所持的任何锁都不会释放。
7)、线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。
8)、同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块。
9)、在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁
分享到:
评论

相关推荐

    android安卓app开发教程之--总结了50条安卓开发经验.zip

    (123代表不同线程,轮流插入一个记录),读和写均不会锁住db,读写交替并没有规律,执行次数和程度看cpu分配给哪个线程的时间片长 43. 选择正确的集合类型使你能够在集合性能与内存占用之间达到合理的平衡。除此...

    2018年面试实战总结.zip

    2018/09/15 周六 下午 15:55 44,123 美联达面试题.docx 2018/11/04 周日 下午 16:17 709,934 轻松搞定JavaWeb面试.docx 2018/12/16 周日 上午 09:31 806,830 达令Java面试.docx 2018/12/14 周五 下午 15:36 62,615 ...

    Java语言基础下载

    内容总结 13 独立实践 14 第二章: 面向对象概述 15 学习目标 15 面向对象(Object Oriented) 16 面向对象的主要特性 18 抽象(Abstraction) 18 封装(Encapsulation): 19 多态(Polymorphism) 20 面向对象的优点 22 ...

    2023最新JAVA面试题集

    多线程面试59题(含答案) 最新JAVA面试题总结之基础/框架/数据库/JavaWeb/Redis BIO,NIO,AIO,Netty面试题 35道 BTA 常问的 Java基础39道常见面试题及详细答案 Dubbo面试题 47道 ElasticSearch面试题 30道 Git常用...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【Redis】redis五种常见的数据类型详解 123 String字符串类型 124 List列表类型 126 Set集合类型 128 Hash散列类型 130 Redis的有序集合ZSet数据类型 131 【Redis】Redis的存储结构,或者说如何工作的,与mysql的...

    J2SE知识点总结(主要帮助初学者)

    包括基础语法、面向对象、异常处理、数组、常用类、容器、IO、反射、枚举类型与泛型、线程、网络、GUI等知识点总结和小例子,另外还附加了J2EE的Servlet、JSP、EL表达式、JSTL标签库、JavaBean的一些知识点,该文档...

    Python从入门到精通-第三章-简单循环

    本资源例题来源于python123.io网站中的课程《Python从入门到精通》,本人通过学习后,总结了学习思路,并在注释上写了详细解释。 《Python从入门到精通》是python123.io网站提供的一套Python编程课程,分为基础篇、...

    Python从入门到精通-第二章-数值运算

    本资源例题来源于python123.io网站中的课程《Python从入门到精通》,本人通过学习后,总结了学习思路,并在注释上写了详细解释。 《Python从入门到精通》是python123.io网站提供的一套Python编程课程,分为基础篇、...

    Python从入门到精通-第五章-流程控制.zip

    本资源例题来源于python123.io网站中的课程《Python从入门到精通》,本人通过学习后,总结了学习思路,并在注释上写了详细解释。 《Python从入门到精通》是python123.io网站提供的一套Python编程课程,分为基础篇、...

    Python从入门到精通-第四章-简单分支.zip

    本资源例题来源于python123.io网站中的课程《Python从入门到精通》,本人通过学习后,总结了学习思路,并在注释上写了详细解释。 《Python从入门到精通》是python123.io网站提供的一套Python编程课程,分为基础篇、...

    Python从入门到精通-第一章-人机交互

    本资源例题来源于python123.io网站中的课程《Python从入门到精通》,本人通过学习后,总结了学习思路,并在注释上写了详细解释。 《Python从入门到精通》是python123.io网站提供的一套Python编程课程,分为基础篇、...

    Delphi5开发人员指南

    5.8 一个消息系统的剖析:VCL 123 5.9 消息与事件之间的关系 128 5.10 总结 129 第6章 代码标准文档 130 6.1 一般的源代码格式规则 130 6.1.1 缩进 130 6.1.2 边距 130 6.1.3 begin...end 130 6.2 Object Pascal 131...

    Java面试题资料合集-44套.rar

    java面试-Java+最常见的+200++面试题汇总+答案总结汇总 java面试-Java并发编程最全面试题 123道 java面试-Java集合框架常见面试题 java面试-Java虚拟机(JVM)面试题 51道 java面试-Kafka知识汇总 18道 java面试-...

    老男孩python 四期

    一、Python运维开发基础课程列表 Python运维开发基础课程列表 第一天 1、编程语言介绍 2、Python基础,介绍历史、...7、课程总结、回顾、期末学生开发运维软件大作业实战 8、期末开发运维软件大作业重点讲解,答疑。

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    11.2.5 总结:类的修饰符 297 11.3 方法的修饰符 297 11.3.1 方法的访问控制符 298 11.3.2 public:没有限制的修饰符 299 11.3.3 protected:仅对子类和同包的类可见 300 11.3.4 默认控制符:仅在本包中可见 ...

    总结了Thread-Callable-Future的小demo

    自留demo,主要是Thread-Callable-Future的基本实现。 参考文章: 1、深入理解Callable ...2、彻底理解Java的Future模式: https://www.cnblogs.com/cz123/p/7693064.html

    c++ 面试题 总结

    ==strcpy拷贝的结束标志是查找字符串中的\0 因此如果字符串中没有遇到\0的话 会一直复制,直到遇到\0,上面的123都因此产生越界的情况 建议使用 strncpy 和 memcpy ---------------------------------------------...

    JAVA基础课程讲义

    线程回顾总结 184 任务调度(补充内容,了解即可!) 184 思考作业 185 上机作业 185 第十章 网络编程 186 基本概念 186 什么是计算机网络 186 计算机网络的主要功能 186 什么是网络通信协议 186 网络通信接口 186 为...

    《Visual Basic 2008应用程序开发实例精讲》全书所有实例程序源代码

    第9章 多线程tcp端口扫描工具243 9.1 实例功能说明243 9.2 设计思路与关键技术244 9.2.1 设计思路244 9.2.2 关键技术244 9.3 程序实现与代码245 9.4 实例总结252 第10章 打造个性化qq的实现253 10.1 实例功能说明253...

Global site tag (gtag.js) - Google Analytics