文章目录
一、前言
多线程的知识点真多啊,整理了一下,发现还是有很多不懂的地方(脑子有点乱,乱的我都不知道都是哪里不懂了),印象最深的,CAS的ABA问题解决方案中:
这个方法:
compareAndSet(预期值,更新值,预期时间戳,更新时间戳)
是在预期值等于更新值的时候返回true吧
那,
代码示例中:
n = new AtomicStampedReference<Integer>(0,0);
Thread t1 = new Thread(){
public void run(){
for(int i=0; i<1000; i++){
int stamp;
Integer reference;
do{
stamp = n.getStamp();
reference = n.getReference();
} while(!n.compareAndSet(reference, reference+1, stamp, stamp+1));
}
}
};
reference和reference+1啥时候能相同啊
目前不懂,希望大佬能够不吝赐教
二、线程安全
(一)多线程特性
多线程编程要保证满足三个特性:原子性、可见性、有序性。
1)原子性
原子性,即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
2)可见性
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。显然,对于单线程来说,可见性问题是不存在的。
3)有序性
程序执行的顺序按照代码的先后顺序执行。
(二)线程安全的定义
如果有多个线程同时运行同一个实现了Runnable接口的类,程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的;反之,则是线程不安全的。
(三)线程安全问题产生的原因
- 多个线程在操作共享数据
- 操作共享数据的线程代码有多条
- 多个线程对共享数据有写操作
(四)解决方法——线程同步
Java中7种线程同步机制
- 同步代码块(synchronized)
- 同步方法(synchronized)
- Lock类
- 特属域变量(volatile)
- 局部变量(ThreadLocal)
- 阻塞队列(LinkedBlockingQueue)
- 原子变量(Atomic)
1、同步代码块(synchronized)
synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
语法:
synchronized(同步锁){
需要同步操作的代码
}
同步锁:对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁
- 锁对象可以是任意类型。
- 多个线程要使用同一把锁。
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。
示例代码:
package com.multithread.thread;
public class Ticket implements Runnable {
private int ticktNum = 100;
//定义锁对象,可以是任意类型,但一定要是对象
Object obj = new Object();
public void run() {
while(true){
synchronized (obj){
//同步代码块
if(ticktNum > 0){
//1.模拟出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.打印进程号和票号,票数减1
String name = Thread.currentThread().getName();
System.out.println("线程"+name+"售票:"+ticktNum--);
}
}
}
}
}
2、同步方法(synchronized)
使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
语法:
public synchronized void method(){
//可能会产生线程安全问题的代码
}
那么,这种方式没有了自定义的同步锁,锁是谁呢?
- 对于非static方法,同步锁就是this(就是调用同步方法的类对象)
- 对于static方法,同步锁是当前方法所在类的字节码对象(类名.class)
示例代码:
package com.multithread.thread;
public class Ticket implements Runnable {
private int ticktNum = 100;
//定义锁对象
// Object obj = new Object();这种方式不需要自定义同步锁
public void run() {
while(true){
sellTicket();
}
}
private synchronized void sellTicket(){
//同步方法
if(ticktNum > 0){
//1.模拟出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.打印进程号和票号,票数减1
String name = Thread.currentThread().getName();
System.out.println("线程"+name+"售票:"+ticktNum--);
}
}
}
3、Lock类
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
3.1Lock接口关系图
-
Lock和ReadWriteLock是两大锁的根接口
-
Lock 接口支持重入、公平等的锁规则:实现类 ReentrantLock、ReadLock和WriteLock。
ReadWriteLock 接口定义读取者共享而写入者独占的锁,实现类:ReentrantReadWriteLock。
3.2Lock类同步锁方法:
public void lock() :加同步锁。
public void