Java 多线程同步的五种方法
https://www.cnblogs.com/zeroingToOne/p/9554560.html 1. 同步方法用synchronized关键字修饰方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。 2. 同步代码块
用synchronized关键字修饰语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 3. Volatile
a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 因为volatile不能保证原子操作导致的,因此volatile不能代替 synchronized。此外volatile会组织编译器对代码优化。它的原理是每次要线程要访问volatile修饰 的变量时都是从内存中读取,而不是存缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步。 4. 使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁
注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 1、ReentrantLock()还可以通过public ReentrantLock(boolean fair)构造方法创建公平锁,即,优先运行等待时间最长的线程,这样大幅度降低程序运行效率。
2、关于Lock对象和synchronized关键字的选择:
(1)、最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。 ??
(2)、如果synchronized关键字能够满足用户的需求,就用synchronized,他能简化代码。
(3)、如果需要使用更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally中释放锁。
5. ThreadLocal
ThreadLocal 类的常用方法
ThreadLocal() : 创建一个线程本地变量
get() : 返回此线程局部变量的当前线程副本中的值
initialValue() : 返回此线程局部变量的当前线程的"初始值"
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
ThreadLocal的原理:
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变 量副本,而不会对其他线程产生影响。
即每个线程运行的都是一个副本,也就是说存钱和取钱是两个账户,只是名字相同而已,两个线程间的count没有关系。所以就会发生上面的效果。
ThreadLocal与同步机制
a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题
b.前者采用以”空间换时间”的方法,后者采用以”时间换空间”的方式
ThreadLocal并不能替代同步机制,两者面向的问题领域不同。
1:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;
2:而threadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享变量,这样当然不需要对多个线程进行同步了。
MySQL查询比较慢的话,通过什么方式来优化
(情况①:偶尔很慢,可能是数据库在查询脏页,或者没拿到锁
情况②:一直很慢,可能是没有索引,或者有索引但没走索引,或者表数据量太大需要分库分表)
客户端和服务器最多能发送和接收多少TCP连接数?
1. 对于服务器,每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,就会返回错误。
我们知道操作系统上端口号1024以下是系统保留的,从1024-65535是用户使用的。由于每个TCP连接都要占一个端口号,所以我们最多可以有60000多个并发连接?但是事实并不是这样。
我们还知道对于TCP连接是由:原IP,原端口,目的IP,目的端口。但是监听server端TCP连接4元组中只有remote ip(也就是client ip)和remote port(客户端port)是可变的,因为它是固定在本地的端口上去监听,所以最大TCP连接为:客户端ip数×客户端port数
2. 而对于客户端,网络通信过程中服务端监听一个固定的端口,客户端主动发起连接请求后要经过三次握手才能与服务器建立起一个TCP连接.客户端每次发起一个TCP连接时,系统会随机选取一个空闲的端口,该端口是独占的不能与其他TCP连接共享,因此理论上一台机器有多少空闲的端口,就能对外发起多少个TCP连接。根据TCP/IP协议,端口port使用16位无符号整数unsigned short来存储,因此本地端口一共有2^16=65536个,即0-65535,其中0~1023是预留端口,0有特殊含义不能使用,1024以下端口都是超级管理员用户(如root)才可以使用,因此就算使用root权限,一台机器最多能使用的端口也只有65535个。但是一台机器最多只能利用28232个端口。具体的细节解释可以看这里https://www.jianshu.com/p/c77e7026531a
怎么做拥塞控制?
怎么进程间通信?
管道:Linux下一切皆文件这我们必须牢记,所以管道就是一份文件,进程A能看到进程B也能够看到,同时进程A往管道中写数据进程B就可以从另一端读数据了。管道又分为匿名管道和命名管道,匿名管道用pipe()创建,只能用于有亲缘关系的进程间通信,而命名管道则是用于任意进程。最后我们可以说一下
命名管道的特点:1、适用于任意进程2、面向字节流3、半双工通信(当然想要实现全双工通信,只要两个管道就可以了)4、生命周期随进程5、内置同步与互斥机制。
消息队列:说白了消息队列就是一个链表,进程A可以向队列中写数据(写满则不能写了,因为消息队列是固定的),队列中有数据了进程B就可以开始读数据了,读完了数据就不能读了(这也就能说明消息队列面向数据报)
消息队列的特点:1、适用于任意进程2、面向数据报3、全双工通信(只要进程有读写权限就可以双向通信)4、生命周期随内核5、内置同步与互斥机制。
共享内存:共享内存就是一块内存,我们知道内存有随机访问的优势,所以共享内存就成为了进程间通信最快的方式。具体通信原理就是这一块物理内存在映射的时候会映射不同的虚拟地址空间,不同的虚拟地址空间就代表着不同的进程那么就可以让多个进程都看到这块内存,然后进行读写操作。
共享内存的特点:1、适用于任意进程2、全双工通信3、生命周期随内核
信号量:信号量准确的来说就没有通信,他可以理解为是一个计数器加上等待队列,它主要侧重了同步于互斥,因为有时候多个进程同时访问临界资源就会产生死锁,那么就需要信号量记录可申请的资源的数量,每申请一次信号量减1,用完释放就加1,等待队列就是资源被申请完了(信号量为0),在申请就会信号量<0,那么此时就会将进程加入等待队列,一旦有资源释放,就可以立马申请到。
信号量的特点就是同步于互斥!!!
其实我个人觉得信号也应该属于进程间通信的一种方式,为什么呢?因为进程控制也是进程间通信的目的之一,那一个进程给另外一个进程发送个9号信号就可以杀死这个进程。
线程池+拒绝策略https://blog.csdn.net/suifeng629/article/details/98884972