-
1.volatile:
当多个线程进行操作共享数据时,可以保证内存中的数据可见 相较于synchronized 是一种较为轻量的同步策略 注意:
volatile 不具备互斥性 volatile 不能保证原子性 作用:
并发中保证有序性和可见性 应用场景:
1.禁止程序指令重排(单例模式的双重锁) 2.保证内存的可见性(操作共享数据时线程之间内存可见)
-
2.CAS算法:
保证数据的原子性(CAS是硬件对于并发操作共享数据的支持)是一种无锁的非阻塞算法的实现CAS包含三个操作(Compare And Swap)
内存值V 预估值A 更新值B 当且仅当V==A时,V = B,否则不做任何操作原子变量(java.util.cuncurrent)包下的类,采用的CAS算法
AtomicInteger...
class AtomicDemo implements Runnable{ // private volatile int i =0; //原子变量 private AtomicInteger i= new AtomicInteger(0); @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(getI()); } public int getI() { return i.getAndIncrement(); } } -
3.ConcurrentHashMap
JDK1.7:采用的锁分段的机制(Segmen)粒度锁,每一个Segment都是HashMap,两次Hash算法 JDK1.8:采用的CAS,无锁机制 用法与HashMap相同 HashTable:锁的是整个表,同步变成异步操作,效率非常低 ConcurrentHashMap ConcurrentSkipListMap ConcurrentSkipListSet CopyOnWriteArrayList :ArrayList 注意:
添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大。并发迭代操作多时可以选择。 CopyOnWriteArraySet -
4.CountDownLatch:
(闭锁)在完成某些运算时,只有其他所有线程完成运算时,当前运算才会进行
使用场景: 在主线程调用其他子线程时,让子线程全部执行完成之后再继续执行主线程。
用法:
CountDownLatch latch = new CountDownLatch(5);
// 调用子线程处理
子线程中调用
try (子线程具体操作内容)
finally {
latch.countDown
}//latch-1
latch.await();
//继续处理主线程
CountDownLatch与join的区别:
调用thread.join() 方法必须等thread 执行完毕,当前线程才能继续往下执行,
而CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行
而不用管相应的thread是否执行完毕。
-
5.Callable:
有返回值,可以抛出异常。 用法:
FutureTask task =new FutureTask<>(new Callable);
new Thread(task).start(); //接收返回值,类似于闭锁操作,必须等线程执行完之后菜会往下执行。 task.get();
-
6.Lock:
用于解决多线程安全问题的方式 用法:
Lock lock=new ReentrantLock(); synchronized:隐式锁
同步代码块 同步方法
Lock:显示锁,需要通过lock()方法上锁,必须通过unlock()方法来释放锁
-
7.wait()
方法应该放在while中,而不是if中。 -
8.Condition
用法:
Lock lock = new ReentrantLock(); //创建lock对象
Condition condition = lock.newCondition(); //获得Lock实例的Condition实例
lock的线程通信
await()
signal()
signalAll()
循環打印ABCABC...
public class TestABCAlternate {
public static void main(String[] args) {
Alternate alternate = new Alternate();
new Thread(()->{
for (int loop = 1;loop <=10; loop++) {
alternate.loopA(loop);
}
}, "A").start();
new Thread(()->{
for (int loop = 1;loop <=10; loop++) {
alternate.loopA(loop);
}
}, "B").start();
new Thread(()->{
for (int loop = 1;loop <=10; loop++) {
alternate.loopA(loop);
}
}, "C").start();
}
}
class Alternate {
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void loopA(int loop) {
lock.lock();
try {
if (number != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// for (int i = 1; i <= 5; i++) {
// System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + loop);
// }
System.out.print(Thread.currentThread().getName());
number = 2;
condition2.signal();
} finally {
lock.unlock();
}
}
public void loopB(int loop) {
lock.lock();
try {
if (number != 2) {
try {
condition2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// for (int i = 1; i <= 10; i++) {
// System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + loop);
// }
System.out.print(Thread.currentThread().getName());
number = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void loopC(int loop) {
lock.lock();
try {
if (number != 3) {
try {
condition3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// for (int i = 1; i <= 15; i++) {
// System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + loop);
// }
System.out.print(Thread.currentThread().getName());
number = 1;
condition1.signal();
} finally {
lock.unlock();
}
}
}
-
9.ReadWriteLock:
读写锁 写写/读写 需要互斥 读读不需要互斥
用法:
ReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
lock.readLock().unlock();
lock.writeLock().lock();
lock.writeLock().unlock();
-
10.线程8锁
两个普通同步方法,两个线程,标准打印, 打印结果? 锁的对象是this(同一把锁) 新增 Thread.sleep() 给 getOne(),打印结果? 锁的对象是this(同一把锁) 新增普通方法 getThree() , 打印结果? 锁的对象是this(同一把锁) getThree无锁 两个普通同步方法,两个 Number 对象,打印结果? 锁的对象是this(不是同一把锁) 修改 getOne() 为静态同步方法,打印结果? 修改两个方法均为静态同步方法,一个 Number 对象,打印结果? 一个静态同步方法,一个非静态同步方法,两个 Number 对象,打印结果? 两个静态同步方法,两个 Number 对象,打印结果? 锁的对象是类对象(是同一把锁)** 所有的非静态同步方法用的都是同一把锁:实例对象本身。**
** 所有的静态同步方法用的也是同一把锁:类对象本身。**
-
11.线程池:
提供了一个线程队列,队列中保存着所有等待的线程, 避免了创建于销毁额外开销,提高了响应的速度。
体系结构
Executor:负责线程的使用与调度的根接口
----ExecutorService 子接口
-----ThreadPoolExecutor 实现类
-----ScheduledExecutorService 子接口:负责线程的调度的子接口
----- ScheduledExecutorExecutor :实现类
Executors 工具类
newFixedThreadPool: 创建固定大小的线程池 (LinkedBlockingQueue)
newCachedThreadPool 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量(SynchronousQueue)
newSingleThreadExecutor 创建单个线程池。线程池中只有一个线程(LinkedBlockingQueue)
newScheduledThreadPool 创建固定大小的线程池,可以延迟或定时执行任务 (DelayQueue)
用法:
ScheduledExecutorService service2 = Executors.newScheduledThreadPool(5);
service2.schedule(new ExecutorPool(), 1, TimeUnit.SECONDS);//延迟1秒执行任务
service2.scheduleAtFixedRate(new ExecutorPool(), 1, 3, TimeUnit.SECONDS);//延迟2秒,每隔1秒执行任务(循环)
执行线程的两种方式(execute和submit)
1.execute提交的是Runnable类型的任务,而submit提交的是Callable或者Runnable类型的任务
2.execute的提交没有返回值,而submit的提交会返回一个Future类型的对象
3.execute提交的时候,如果有异常,就会直接抛出异常,而submit在遇到异常的时候,
通常不会立马抛出异常,而是会将异常暂时存储起来,等待你调用Future.get()方法的时候,才会抛出异常
submit可以查看执行是否成功
ThreadPoolExecutor 参数:
int corePoolSize :该线程池中核心线程数最大值(核心线程默认情况下会一直存活在线程池中)
int maximumPoolSize:线程总数最大值
long keepAliveTime:非核心线程闲置超时时长
TimeUnit unit:闲置时长的单位
BlockingQueue<Runnable> workQueue:该线程池中的任务队列:维护着等待执行的Runnable对象
ThreadFactory threadFactory
RejectedExecutionHandler handler:抛出异常
workQueue类型:
SynchronousQueue:队列接接收任务,直接提交给线程。
LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,
则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。
队列没有限制
ArrayBlockingQueue:队列满了就则新建线程(非核心线程)执行任务。
DelayQueue:这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
RejectedExecutionHandler handler:
AbortPolicy:直接抛出异常,这是默认策略;
CallerRunsPolicy:用调用者所在的线程来执行任务;
DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
DiscardPolicy:直接丢弃任务