案例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SaleTicketDemo {
public static void main(String[] args) throws InterruptedException{
Ticket ticket = new Ticket();
ExecutorService executorService = Executors.newFixedThreadPool(50);
for (int j = 0; j < 50; j++) {
executorService.execute(()->{
for (int i = 0; i < 20; i++) {
ticket.sale();
}
});
}
Thread.sleep(2000);
System.out.println(ticket.number);
System.out.println(CountTest.count);
executorService.shutdown();
}
}
class Ticket {
public int number = 10;
public void sale(){
try {
Thread.sleep(100);
} catch (Exception e){
e.printStackTrace();
}
if(number > 0){
System.out.println(Thread.currentThread().getName() + "剩余:" + number--);
synchronized (CountTest.class){
CountTest.count++;
}
}
}
}
class CountTest{
public volatile static int count = 0;
}
当线程数量大于500进入if(number > 0),说明线程操作数据大于500次,不符合预期值,存在多线程安全问题。
Synchronized 和 Lock 区别
1. synchronized 内置java关键字;Lock 是一个java类;
2. synchronized 无法判断获取锁的状态;Lock 可以判断是否获取到了锁;
3. synchronized 会自动释放锁;Lock 必须手动释放锁,如果不释放,死锁;
4. synchronized 线程会一直等待锁;Lock 不一定等待下去;
5. synchronized 可重入锁,不可以中断,非公平;Lock 可重入锁,可以判断锁,非公平或者公平;
6. synchronized 适合少量代码同步问题;Lock 适合大量同步代码;
Lock实现类
ReentrantLock(可重入锁), ReentrantReadWriteLock.ReadLock(读锁), ReentrantReadWriteLock.WriteLock(写锁)
ReentrantLock
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- 公平锁:先来后到;
- 非公平锁:可以插队;
虛假唤醒
不能用if判断,要用while判断;可以查看jdk文档;
生产者和消费者
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
Condition condition = lock.newCondition();
condition.await();
condition.signalAll();
**如果需要按顺序执行,可以创建多个Condition**
异常
java.util.ConcurrentModificationException
集合
ArraryLsit 线程不安全;
- List<String> list = new ArrayList<>();
- List<String> list = new Vector<>();
- List<String> list = Collections.synchronizedList(new ArrayList<>());
- List<String> list = new CopyOnWriteArrayList<>();
HashSet 线程不安全;
- 同ArraryLsit
HashMap 线程不安全;
-Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
-Map<String,String> map = new ConcurrentHashMap();
CopyOnWriteArrayList:写入时复制-COW,计算程序设计领域的一种优化策略;
CopyOnWriteArrayList底层用的ReentrantLock,Vector底层用的synchronized;
ArrayList底层扩展原理:Arrays.copyOf(elementData, newCapacity);
HashSet底层原理就是return map.put(e, PRESENT)==null;
接口Callable
java.util.concurrent.FutureTask
类型参数:
V - 此 FutureTask 的 get 方法所返回的结果类型。
已实现的接口: **Runnable**
FutureTask(Callable callable)
创建一个 FutureTask,一旦运行就执行给定的 Callable。
特点:
- 可以返回结果,但是有可能造成阻塞;
- 可以抛出异常;
- 结果可被缓存;