说了无数次高并发,每次都是断断续续。今天打算好好来学习记录一下。
高并发三个知识点:同步器synchronizer / 同步容器 / 线程池
课程地址:http://www.sxt.cn/concurrence/4-8.html
synchronized关键字
- .对象o的锁
Object o = new Object();
synchronized(o){
...
}
- .this 锁定当前对象 当前对象指谁?看下验证代码
synchronized(this){
}
动手实验:结果是锁定方法所在类的对象(本类对象调用本类方法)
public class MyService {
public void myMethod() {
/**
* 验证this锁定的是那个对象
* 经过实验,this,锁定的是方法所在类的对象(即:MyService对象)
* 1.web中要锁定的对象是否为单例
* 2.同类中的其他synchronized(this)修饰符也会被锁定
*/
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println("I : " + i + " thread Name:{}" + Thread.currentThread().getName());
}
}
}
}
public class MyThreadA implements Runnable {
MyService sev;
MyThreadA(MyService sev) {
this.sev = sev;
}
@Override
public void run() {
sev.myMethod();
}
}
public class Main {
public static void main(String[] args) {
MyService sev = new MyService();
Thread t1 = new Thread(new MyThreadA(sev));
t1.start();
MyService sev2 = new MyService();
//Thread t2 = new Thread(new MyThreadB(sev2));
// t1 和 t2 才会加共同的锁
Thread t2 = new Thread(new MyThreadB(sev));
t2.start();
}
}
小结:对象锁锁定的对象属性变化时,对锁定对象无影响。但是对象发生变化时锁就会失效。
对象锁锁定的是堆方法中的对象实体,并非栈内存的对象引用。
- 修饰普通方法 (对象锁)
// 同样锁定是本类对象
public synchronized void get(){
}
- 修饰静态方法 (类锁)
// 锁定的是T.class 也就是类级别的锁
public synchronized static void set(){
}
小结:synchronized保证了原子性和可见性
volatile关键字
内存可见性,禁止重排序
保证线程对vloatile修饰变量的操作及时刷回主内存,并且作废其他线程缓存区的缓存。(主要是后面步骤)
AtomXXX
原子类,用于计数。
不能以字符串常量加锁
String s1="111";
String s2="111";
s1&s2是同一个对象的锁
wait & notify
Object lock = new Object();
synchronized(lock){
}
lock.wait();//让 获得lock锁的当前线程 等待,释放lock锁
lock.notify();// 启动正在对象上等待的线程 或者notifyAll() 但是不会释放锁
CountDownLatch
//加上了2道门栅
CountDownLatch latch = new CountDownLatch(2);
latch.await(); // 必须等所有的门栅释放完完才会唤醒
latch.countDown();// 调用一次释放一道门栅
Reentrantlock 显示锁
Lock lock = new ReentrantLock();
// 必须手动加锁和释放锁
lock.lock();
lock.unlock();
可以使用tryLock() 判断是否能获取锁。返回boolean类型值做不同的业务处理。
概念解释:
公共锁:先来先得。线程A释放了锁,其他等待锁的线程里谁最先来等待的,谁获取这个锁。
Lock lock = new ReentrantLock(true);//表示公平锁
非公平锁:随机分配。线程A释放了锁,其他等待锁的线程随机获取这个锁。
ThreadLocal
线程局部变量,每个线程自己保存一份
网友评论