juc指 java.util.concurrent包
线程与进程
进程:一个程序的集合,一个进程往往可以包含多个线程,至少包含一个
线程:是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
Java启动线程的三种方式:
继承Thread类
实现Runnable类
实现callable类
Java是不能开启线程的,源码展示
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
//本地方法调用底层的C++,java无法直接操作硬件
private native void start0();
并发与并行
并发:(多线程操作同一资源)
Cpu单核,模拟出条多线程
并行(多个人一起走)
Cup多核,多个线程可以同时执行
public class TestCPU {
public static void main(String[] args) {
//获取CPU的核数:CPU密集型 IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用CPU的资源
线程的状态
public enum State {
/**
* Thread state for a thread which has not yet started. 新生
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor. 运行
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}. 阻塞
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
*
* - {@link Object#wait() Object.wait} with no timeout
* - {@link #join() Thread.join} with no timeout
* - {@link LockSupport#park() LockSupport.park}
*
*
* A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called Object.wait()
* on an object is waiting for another thread to call
* Object.notify() or Object.notifyAll() on
* that object. A thread that has called Thread.join()
* is waiting for a specified thread to terminate. 等待,死死的等 with no timeout
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
*
* - {@link #sleep Thread.sleep}
* - {@link Object#wait(long) Object.wait} with timeout
* - {@link #join(long) Thread.join} with timeout
* - {@link LockSupport#parkNanos LockSupport.parkNanos}
* - {@link LockSupport#parkUntil LockSupport.parkUntil}
*
waiting time 限时等待
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution. 终止
*/
TERMINATED;
}
来自不同的类 :wait是Object类的;sleep是Thread类的
锁的释放:Wait会释放锁,sleep不会释放锁(等是醒着的,睡着了就不知道释放了)
使用范围:wait只能在同步代码块中;sleep任何地方都可以(等至少要有个事情,睡任何地方都可以睡)
异常捕获:wait不需要,sleep必须要捕获异常
代码示例
/**
* 真正的多线程开发:线程就是一个单独的资源类,没有任何附属的操作
*/
public class SaleTicketDemo1 {
public static void main(String[] args) {
Ticket ticket = new Ticket();
//@FunctionalInterface 函数式接口 lambda表达式(参数)->{代码}
new Thread(() ->{
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
},"A").start();
new Thread(() ->{
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
},"B").start();
new Thread(() ->{
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
},"C").start();
}
}
//OOP
class Ticket{
int num = 30;
public synchronized void saleTicket(){
if(num>0){
System.out.println(Thread.currentThread().getName()+"已经卖出"+num--+",剩余"+num);
}
}
}
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*
* new NonfairSync() --》非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*
* new FairSync()--》公平锁
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁:十分公平;先来后到
非公平锁:不公平;可以插队(默认);(如果来了两个线程一个3h,一个3s那么插队更好)
Lock 使用代码示例
public class SaleTicketDemo2 {
public static void main(String[] args) {
Ticket2 ticket = new Ticket2();
new Thread(() ->{for (int i = 0; i < 40; i++) ticket.saleTicket();},"A").start();
new Thread(() ->{for (int i = 0; i < 40; i++) ticket.saleTicket();},"B").start();
new Thread(() ->{for (int i = 0; i < 40; i++) ticket.saleTicket();},"C").start();
}
}
//三步曲 1创建Lock new ReentrantLock() 2加锁lock.lock() 3 解锁 lock.unlock();
class Ticket2{
int num = 30;
// 1 创建Lock
Lock lock = new ReentrantLock();
public void saleTicket(){
//2 加锁
lock.lock();
try{//业务代码
if(num>0){
System.out.println(Thread.currentThread().getName()+"已经卖出"+num--+",剩余"+num);
}
}catch (Exception e){
e.printStackTrace();
}finally {//解锁
lock.unlock();
}
}
}
1 Synchronized 内置的Java关键字,lock是一个类
2 Synchronized无法判断获取锁的状态,lock可以判断是否获取到了锁
3 Synchronized会自动释放锁,lock必须要手动释放锁(如果不释放,死锁)
4 Synchronized线程1(获得锁,阻塞)、线程2(等待,一直等);lock锁就不一定会等待下去
5 Synchronized可重入锁,不可以中断,非公平;Lock可重入锁,可以判断锁,非公平(可以自己设置)
6 Synchronized适合锁少量的代码同步问题;lock适合锁大量的同步代码
代码示例
/**
* 线程之间的通信问题:生产和消费者问题 等待唤醒 通知唤醒
* 线程交替执行AB 操作同一个变量 num = 0
*/
public class TestPC {
public static void main(String[] args){
Data data = new Data();
new Thread(()->{ for (int i = 0; i < 5; i++)data.increment();},"A").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.decrement();},"B").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.increment();},"C").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.decrement();},"D").start();
}
}
//等待,业务,通知
class Data{
private int num = 0;
//+1
public synchronized void increment(){
if(num != 0){//等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num++;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我+1完成
this.notifyAll();
}
//-1
public synchronized void decrement(){
if(num == 0){//等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我-1完成
this.notifyAll();
}
}
信息打印
当只有AB线程时:
当有ABCD线程时
存在的问题 当AB两个线程正常打印信息,当ABCD四个线程时就有问题了(虚假唤醒)
因为if只判断了一次
解决办法将if改为while
/**
* 线程之间的通信问题:生产和消费者问题 等待唤醒 通知唤醒
*/
public class TestPC {
public static void main(String[] args){
Data data = new Data();
new Thread(()->{ for (int i = 0; i < 5; i++)data.increment();},"A").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.decrement();},"B").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.increment();},"C").start();
new Thread(()->{ for (int i = 0; i < 5; i++)data.decrement();},"D").start();
}
}
//等待,业务,通知
class Data{
private int num = 0;
//+1
public synchronized void increment(){
while(num != 0){//等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num++;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我+1完成
this.notifyAll();
}
//-1
public synchronized void decrement(){
while(num == 0){//等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我-1完成
this.notifyAll();
}
}
public class JUCTestPC {
public static void main(String[] args){
Data1 data = new Data1();
new Thread(()->{ for (int i = 0; i < 10; i++)data.increment();},"A").start();
new Thread(()->{ for (int i = 0; i < 10; i++)data.decrement();},"B").start();
new Thread(()->{ for (int i = 0; i < 10; i++)data.increment();},"C").start();
new Thread(()->{ for (int i = 0; i < 10; i++)data.decrement();},"D").start();
}
}
//等待,业务,通知
class Data1{
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//+1
public void increment(){
lock.lock();
try {
while(num != 0){//等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我+1完成
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void decrement(){
lock.lock();
try {
while(num == 0){//等待
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+"->"+num);
//通知其他线程,我-1完成
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
代码示例
public class JUCTestConditionPC {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(()->{ for (int i = 0; i < 5; i++) data3.printA(); },"A").start();
new Thread(()->{ for (int i = 0; i < 5; i++) data3.printB(); },"B").start();
new Thread(()->{ for (int i = 0; i < 5; i++) data3.printC(); },"C").start();
}
}
class Data3{
private int num = 1;
private Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void printA(){
lock.lock();
try {
while(num!=1){
condition1.await();
}
num = 2;
System.out.println(Thread.currentThread().getName()+"->AAA");
condition2.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while(num!=2){
condition2.await();
}
num = 3;
System.out.println(Thread.currentThread().getName()+"->BBB");
condition3.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while(num!=3){
condition3.await();
}
num = 1;
System.out.println(Thread.currentThread().getName()+"->CCC");
condition1.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 1.标准情况下,两个线程先打印发短信还打电话
*/
public class Test1_Synchronized {
public static void main(String[] args) {
Phone1 phone = new Phone1();
new Thread(()->{ phone.sendMessage();},"A").start();
new Thread(()->{ phone.call();},"B").start();
}
}
class Phone1 {
//synchronized 锁的对象是方法的调用者
//两个方法用的是同一个锁,谁先拿到谁执行!
public synchronized void sendMessage(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
打印信息
总结:
1 synchronized 锁的对象是方法的调用者
2 两个方法用的是同一个锁,谁先拿到谁执行!
/**
* 2.sendMessage延迟4秒,两个线程先打印发短信还打电话
*/
public class Test2_Synchronized {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{ phone.sendMessage();},"A").start();
new Thread(()->{ phone.call();},"B").start();
}
}
class Phone2 {
//synchronized 锁的对象是方法的调用者
//两个方法用的是同一个锁,谁先拿到谁执行!
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
打印信息
小结:
1 synchronized 锁的对象是方法的调用者
2 两个方法用的是同一个锁,谁先拿到谁执行! 不管你延时多久,A先拿到方法就先执行
/**
* 3增加一个普通方法后,先执行发短信还是say hello
*/
public class Test3_Synchronized {
public static void main(String[] args) {
Phone3 phone = new Phone3();
new Thread(()->{ phone.sendMessage();},"A").start();
new Thread(()->{ phone.call();},"B").start();
new Thread(()->{ phone.hello();},"C").start();
}
}
class Phone3 {
//synchronized 锁的对象是方法的调用者
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//这里没有锁;不是同步方法,不受锁的影响
public void hello(){
System.out.println("say hello");
}
}
打印信息
小结:
1 synchronized 锁的对象是方法的调用者
2 普调方法没有锁;不是同步方法,不受锁的影响
/**
* 4两个线程先打印发短信还打电话
*/
public class Test4_Synchronized {
public static void main(String[] args) {
//两个对象 两个调用者 两把锁
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(()->{ phone1.sendMessage();},"A").start();
new Thread(()->{ phone2.call();},"B").start();
}
}
class Phone4 {
//synchronized 锁的对象是方法的调用者
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
/**
* 5两个线程先打印发短信还打电话 只有一个对象的情况
*/
public class Test5_Synchronized {
public static void main(String[] args) {
Phone5 phone1 = new Phone5();
new Thread(()->{ phone1.sendMessage();},"A").start();
new Thread(()->{ phone1.call();},"B").start();
}
}
//Phone4唯一的一个Class模板
class Phone5 {
//synchronized static静态方法 类加载就有了!锁的是Class模板
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
/**
* 6两个线程先打印发短信还打电话 两个对象情况
*/
public class Test6_Synchronized {
public static void main(String[] args) {
//两个对象的Class类模板只有一个, static锁的是Class
Phone6 phone1 = new Phone6();
Phone6 phone2 = new Phone6();
new Thread(()->{ phone1.sendMessage();},"A").start();
new Thread(()->{ phone2.call();},"B").start();
}
}
class Phone6 {
//synchronized static静态方法 类加载就有了!锁的是Class模板
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
/**
* 7两个线程先打印发短信还打电话 一个对象情况 一个静态方法 一个普通方法
*/
public class Test7_Synchronized {
public static void main(String[] args) {
Phone7 phone1 = new Phone7();
new Thread(()->{ phone1.sendMessage();},"A").start();
new Thread(()->{ phone1.call();},"B").start();
}
}
class Phone7 {
//静态同步方法 锁的是Class模板
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通的同步方法 锁的调用者
public synchronized void call(){
System.out.println("打电话");
}
}
/**
* 8两个线程先打印发短信还打电话 一个对象情况 一个静态方法 一个普通方法
*/
public class Test8_Synchronized {
public static void main(String[] args) {
//两个对象的Class类模板只有一个, static锁的是Class
Phone8 phone1 = new Phone8();
Phone8 phone2 = new Phone8();
new Thread(()->{ phone1.sendMessage();},"A").start();
new Thread(()->{ phone2.call();},"B").start();
}
}
class Phone8 {
//静态同步方法 锁的是Class模板
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通的同步方法 锁的调用者
public synchronized void call(){
System.out.println("打电话");
}
}
总结
New this具体的对象实例,调用者
Static class唯一的一个模板
代码示例
public class TestList {
public static void main(String[] args) {
/**
* 解决办法:
* 1 用Vector,其实就是加了synchronized锁
* 2.Collections.synchronizedList(new ArrayList<>())解决
* 3.new CopyOnWriteArrayList<>()
*/
//List list = new ArrayList<>();
//List list = new Vector<>();
//List list = Collections.synchronizedList(new ArrayList<>());
//CopyOnWrite 写入时复制 cow 计算机程序设计领域 的一种优化策略
//多个线程调用的时候,list,读取的时候,固定写入(覆盖);在写入时覆盖避免造成数据问题
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
打印信息
ArrayList
Vector
Collections.synchronizedList(new ArrayList<>())
CopyOnWriteArrayList
总结
ArrayList在多线程情况下可能会出现异常且不安全,没有全部成功添加,长度不够30
其他情况的list正常
源码解析
Vector 用的同步方法 synchronized
/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
CopyOnWriteArrayList 使用的 ReentrantLock
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
hasSet底层是什么–》(map的key不重复)
/**
* Constructs a new, empty set; the backing HashMap instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element e to this set if
* this set contains no element e2 such that
* (e==null ? e2==null : e.equals(e2)).
* If this set already contains the element, the call leaves the set
* unchanged and returns false.
*
* @param e element to be added to this set
* @return true if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
代码示例
/**
* 解决线程安全的办法
* 1Collections.synchronizedSet(new HashSet<>());
* 2new CopyOnWriteArraySet<>();
*/
public class TestSet {
public static void main(String[] args) {
//Set set = new HashSet<>();
//Set set = Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
代码示例
/**
* 解决办法:
* 1 Collections.synchronizedMap(new HashMap<>());
* 2 new Hashtable<>() 底层运用synchronized
* 3 new ConcurrentHashMap<>()
*/
public class TestMap {
public static void main(String[] args) {
//new HashMap<>(16,0.75f) 默认容量16,加载因子 0.75f
//Map map = new HashMap<>();
//Map map = new Hashtable<>();
//Map map = Collections.synchronizedMap(new HashMap<>());
Map<String,Object> map = new ConcurrentHashMap<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
1.可以有返回值
2.可以抛出异常
3.方法不同,run()/call()
代码示例
public class TestCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//new Thread(new Runnable()).start();
//new Thread(new FutureTask()).start();
//new Thread(new FutureTask(Callable)).start();
MyThread thread = new MyThread();
FutureTask task = new FutureTask(thread);//适配类
new Thread(task,"A").start();
new Thread(task,"B").start();//结果会被缓存,效率高 所以只输出一次call方法
//这个get方法可能会产生阻塞!把他放到最后;或者用异步通信来处理
Integer o =(Integer) task.get();
System.out.println(o);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call方法");
return 1024;
}
}
public class TestCountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//总数是7 ,必须要执行完任务的时候再继续往下走
CountDownLatch countDownLatch = new CountDownLatch(7);
for (int i = 0; i < 7; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" Go out!!!");
countDownLatch.countDown();//数量-1
},String.valueOf(i)).start();
}
countDownLatch.await();//等待计数器归0,然后再向下执行
System.out.println("close door");
}
}
信息打印
如注释掉 countDownLatch.await();
注意当new CountDownLatch(7) 当7大于线程数时就会卡在线程处一直不结束
原理
CountdownLatch.countdown()//数量-1
CountdownLatch.await()//等待计数器归零,然后再向下执行
每次有线程调用countdown数量-1,假设计数器变为0,CountdownLatch.await()就会被唤醒,继续执行下面的代码;
public class TestCyclicBarrierDemo {
public static void main(String[] args){
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("集齐成功,召唤神龙");
});
for (int i = 0; i < 7; i++) {
final int temp = i;//定义一个临时变量,lambda里面可以访问
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集"+temp+"龙珠");
try {
cyclicBarrier.await();//等待
} catch (Exception e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
信号量
代码示例
public class TestSemaphore {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 4; i++) {
new Thread(()->{
try {
semaphore.acquire();//获得
System.out.println(Thread.currentThread().getName()+"抢到了车位");
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"离开了车位");
} catch (Exception e) {
e.printStackTrace();
}finally {
semaphore.release();//释放
}
}).start();
}
}
}
semaphore.acquire();//获得,假如已经满了,等待,等到释放为止
semaphore.release();//释放,会将当前的信号量释放+1,然后召唤等待的线程
作用:多个共享资源互斥的使用!并发限流,控制最大的线程数
/**
* 独占锁(写锁) 一次只能被一个线程占有
* 共享锁(读锁) 多个线程可以同时占用
* ReadWriteLock
* 读-读 可以共享
* 读-写 不能共享
* 写-写 不能共享
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
MyCacheLock myCacheLock = new MyCacheLock();
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myCacheLock.put(temp+"",temp);
},String.valueOf(i)).start();
}
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myCacheLock.get(temp+"");
},String.valueOf(i)).start();
}
}
}
//自定义锁缓存
class MyCacheLock {
private volatile Map<String,Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//写入时,只希望同时只有一个线程写
public void put(String key,Object value){
readWriteLock.writeLock().lock();
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
readWriteLock.writeLock().unlock();
}
//读取时,所有都线程都可以读
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
}
}
//普通自定义缓存
class MyCache {
private volatile Map<String,Object> map = new HashMap<>();
public void put(String key,Object value){
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
}
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
}
}
MyCache 信息打印
该方式存在插入并发问题
MyCacheLock 信息打印
写入:如果队列满了,就必须阻塞等待
取:如果是队列是空的,必须阻塞等待生产
BlockingQueue
使用队列
添加 移除
四组API
方式 | 抛出异常 | 有返回值(不抛出异常) | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer(失败返回false) | put | offter(…) |
移除 | remove | poll(没有返回null) | take | poll(…) |
检查队首元素 | element | peek | - | - |
代码示例
public class TestBlockingQueue {
public static void main(String[] args) throws InterruptedException {
test1();
}
//有返回值 抛出异常
public static void test1(){
BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
System.out.println(blockingQueue.add("a"));//true
System.out.println(blockingQueue.add("b"));//true
System.out.println(blockingQueue.add("c"));//true
//System.out.println(blockingQueue.add("d")); //java.lang.IllegalStateException: Queue full 超长跑异常
System.out.println("--------------------------");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove()); //java.util.NoSuchElementException
}
}
public class TestBlockingQueue {
public static void main(String[] args) throws InterruptedException {
test2();
}
//有返回值 不抛异常
public static void test2(){
BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
System.out.println(blockingQueue.offer("a"));//true
System.out.println(blockingQueue.offer("b"));//true
System.out.println(blockingQueue.offer("c"));//true
System.out.println(blockingQueue.offer("d"));//false
System.out.println("-----------------------");
System.out.println(blockingQueue.poll());//a
System.out.println(blockingQueue.poll());//b
System.out.println(blockingQueue.poll());//c
System.out.println(blockingQueue.poll());//null
}
}
public class TestBlockingQueue {
public static void main(String[] args) throws InterruptedException {
test3();
}
//阻塞等待
public static void test3() throws InterruptedException {
BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
//blockingQueue.put("d");//超过长度一致等待入队 程序不结束
System.out.println("---------------------");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());//超过长度一致等待取值 程序不结束
}
}
public class TestBlockingQueue {
public static void main(String[] args) throws InterruptedException {
test4();
}
//超时等待
public static void test4() throws InterruptedException {
BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
System.out.println(blockingQueue.offer("a", 3, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("b", 3, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("c", 3, TimeUnit.SECONDS));
//System.out.println(blockingQueue.offer("d", 3, TimeUnit.SECONDS));//超过长度设置等待入队时间 程序过时自动结束
System.out.println("---------------------");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));//超过长度设置等待取值时间 程序过时自动结束
}
}
test4信息打印
SynchronousQueue同步队列
没有容量
进去一个元素,必须等取出来之后,才能继续存放
代码示例
public class TestSynchronousQueue {
public static void main(String[] args) {
BlockingQueue<String> synchronousQueue = new SynchronousQueue<String>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+" put 1");
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName()+" put 2");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName()+" put 3");
synchronousQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"-->"+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"-->"+synchronousQueue.take());
TimeUnit.SECONDS.sleep(4);
System.out.println(Thread.currentThread().getName()+"-->"+synchronousQueue.take());
} catch (Exception e) {
e.printStackTrace();
}
},"B").start();
}
}
线程池:三大方法、7大参数、4种拒绝策略
池化技术
程序的运行,本质:占用系统的资源!优化资源的使用
线程池、连接池,内存池、对象池…
池化技术:事先准备好一些资源,有人要用,就来池里取,用完之后还给池里
线程池的好处
降低资源的消耗
提高响应的速度
方便管理
线程服用、可以控制最大并发数,管理线程
public class ThreadStartWay {
public static void main(String[] args) {
ExecutorService service1 = Executors.newSingleThreadExecutor();//单个线程
ExecutorService service2 = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
ExecutorService service3 = Executors.newCachedThreadPool();//可伸缩的,遇强则强
try {
for (int i = 0; i < 30; i++) {
service3.execute(()->{
System.out.println(Thread.currentThread().getName()+" hello");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
service3.shutdown();
}
}
}
单个线程底层源码
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
固定线程池
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
缓存线程池
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
总结:本质都是通过ThreadPoolExecutor()
源码
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
int maximumPoolSize,//最大核心线程池大小
long keepAliveTime,//超时了没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂,创建线程的,一般不用动
RejectedExecutionHandler handler) {//拒绝策略
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
new ThreadPoolExecutor.AbortPolicy();//队列人满了,还来人,不处理了,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy();//哪儿来去哪儿
new ThreadPoolExecutor.DiscardOldestPolicy();//队列满了,丢掉任务,不抛异常
new ThreadPoolExecutor.DiscardPolicy();//队列满了,尝试和去最早的竞争,不会抛异常
手动创建一个线程池
代码示例
public class ThreadPoolDemo {
public static void main(String[] args) {
int core = Runtime.getRuntime().availableProcessors();
ExecutorService threadPool = new ThreadPoolExecutor(
core,core*4,3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(core),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
try {
for (int i = 0; i < 20; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"!");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
CPU密集型 与 IO密集型
1cpu密集型,几核就是几,可以保持cpu的效率最高!
获取cup的多少核:Runtime.getRuntime().availableProcessors();设置最大核心线程池大小
2 io 密集型,判断你的程序中十分耗IO的线程
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
代码示例
/**
* 函数式接口 输入一个参数,返回一个参数
*/
public class FunctionDemo01 {
public static void main(String[] args) {
Function<String,String> function1 = new Function<String,String>() {
@Override
public String apply(String str) {
return str;
}
};
Function<String,String> function2 =(str)->{return str;};
Function<String,String> function3 = str->{return str;};
System.out.println(function1.apply("hello world 1 !"));
System.out.println(function2.apply("hello world 2 !"));
System.out.println(function3.apply("hello world 3 !"));
}
}
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
代码示例
/**
* 断定型接口 输入一个参数,返回boolean
*/
public class PredicateDemo02 {
public static void main(String[] args) {
Predicate<String> predicate1 = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};
Predicate<String> predicate2 = (str)->{return str.isEmpty();};
Predicate<String> predicate3 = str->{return str.isEmpty();};
System.out.println(predicate1.test(""));//true
System.out.println(predicate2.test("123"));//false
System.out.println(predicate3.test(""));//true
}
}
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
代码示例
/**
* 消费者 只有输入 没有返回值
*/
public class ConsumerDemo03 {
public static void main(String[] args) {
Consumer<String> consumer1 = new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
};
Consumer<String> consumer2 = (str)->{System.out.println(str);};
Consumer<String> consumer3 = str->{System.out.println(str);};
consumer1.accept("1123");
consumer2.accept("avs");
consumer3.accept("ava212");
}
}
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
代码示例
/**
* 供给型 没有传入参数,只有返回参数
*/
public class SupplierDemo04 {
public static void main(String[] args) {
Supplier<String> supplier1 = new Supplier<String>() {
@Override
public String get() {
System.out.println("o(* ̄︶ ̄*)o");
return "wo cao";
}
};
Supplier<String> supplier2 =()->{return "wo cao";};
Supplier<String> supplier3 =()->{return "wo cao";};
System.out.println(supplier1.get());
System.out.println(supplier2.get());
System.out.println(supplier3.get());
}
}
信息打印
代码示例
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
/**
* 一行代码实现
* 1id为偶数
* 2年龄大于23
* 3用户名转为大写
* 4用户名字母倒序
* 5只输出一个用户
*/
public class StreamDemo1 {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(5,"e",25);
User u6 = new User(6,"f",26);
List<User> usersList = Arrays.asList(u1, u2, u3, u4, u5, u6);
usersList.stream()
.filter(u->{return u.getId()%2==0;})
.filter(u->{return u.getAge()>23;})
.map(u->{return u.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
信息打印
ForkJoin (拆分任务)
Forkjoin特点:工作窃取
双端队列
Future:对将来的某个事件结果进行建模
代码示例
public class FutureTest01 {
public static void main(String[] args) {
//没有返回值 runAsync 异步回调
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=>runAsync");
});
System.out.println("1233");
try {
voidCompletableFuture.get();//获取阻塞执行结果
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class FutureTest02 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName()+"=>supplyAsync");
//int i = 10/0;
return 200;
});
System.out.println(completableFuture.whenComplete((t, u) -> {
System.out.println("t=>" + t);// 200 成功返回值
System.out.println("u=>" + u);// 错误信息 java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
}).exceptionally((e) -> {
System.out.println("message=>" + e.getMessage());
return 500;
}).get());
}
}
volatile是Java虚拟机提供轻量级的同步机制
1保证可见性
2不保证原子性
3禁止指令重排
什么是JMM
JMM:java内存模型
关于jmm的一些同步的约定:
1 线程解锁前,必须把共享变量立刻刷回主存
2 线程加锁前,必须读取主存中的最新值到工作内存中!
3 加锁解锁是同一把锁
线程 工作内存 主内存 8种操作:
/**
* volatile可以保证可见性
*/
public class JMMDemo01 {
//不加volatile程序会进入死循环,加上volatile可以保证可见性
private volatile static int num = 0;
public static void main(String[] args) {
new Thread(()->{//线程对主内存中num的值的变化不知道的,所以线程一直运行
while(num == 0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num);
}
}
但是在while中打印信息程序又会停止,为什么?
原子性 不可分割
线程A在执行任务的时候,不能被打扰,也不能被分割;要么同时成功,要么同时失败。
/**
* volatile不保证原子性
*/
public class JMMDemo02 {
//volatile保证可见性,不保证原子性
private volatile static int num = 0;
private static void add(){
num++;//不是原子性操作
}
public static void main(String[] args) {
//理论上值为20000
for (int i = 0; i < 20; i++) {
new Thread(()->{
for (int j = 0; j <1000 ; j++) {
add();
}
}).start();
}
while (Thread.activeCount()>2){//main gc 在运行
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+ " "+ num);
}
}
/**
* AtomicInteger原子类解决问题
*/
public class JMMDemo03 {
//volatile保证可见性,不保证原子性
//private volatile static int num = 0;
//用原子类解决问题
private static AtomicInteger num = new AtomicInteger();
private static void add(){
//num++;
num.getAndIncrement();// AtomicInteger+1 方法 CAS
}
public static void main(String[] args) {
//理论上值为20000
for (int i = 0; i < 20; i++) {
new Thread(()->{
for (int j = 0; j <1000 ; j++) {
add();
}
}).start();
}
while (Thread.activeCount()>2){//main gc 在运行
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+ " "+ num);
}
}
信息打印
这些类的底层都直接和操作系统挂钩,在内存中修改值!Unsafe是一个特殊的类
什么是指令重拍:你写的程序,计算机并不是按照你写的那样去执行的
源代码->编译器优化的重排->指令并行也可能会重排->内存系统也会重排->执行
处理器在进行指令重排的时候;会优先考虑数据之间的依赖性!
int x = 1;//1
int y = 2;//2
x = x + 5;//3
y = x * y;//4
//我们期望顺序是1234 但是可能执行顺序是 2134 1324
可能造成影响的结果:a b x y 四个值都为0;
线程A | 线程B |
---|---|
x=a | y=b |
b=1 | a=2 |
正常结果:x = 0 y = 0; 但是指令重排
线程A | 线程B |
---|---|
b=1 | a=2 |
x=a | y=b |
指令重排导致结果: x = 2 y = 1;
Volatile 可以避免指令重排
1 保证特定的操作的执行顺序!
2 可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)
Volatile是可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生
//饿汉式单列模式
public class HungrySingle {
private HungrySingle(){
System.out.println(Thread.currentThread().getName()+"->创建");
}
private final static HungrySingle HUNGRY_SINGLE = new HungrySingle();
public static HungrySingle getHungrySingle(){
return HUNGRY_SINGLE;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
HungrySingle instance = HungrySingle.getHungrySingle();
}).start();
}
}
}
//懒汉模式~不双重校验不安全
public class LazyMan01 {
private LazyMan01(){
System.out.println(Thread.currentThread().getName() + "->创建");
}
private static LazyMan01 lazyMan;
//不加双重校验在多线程下不安全
public static LazyMan01 getInstance(){
if(lazyMan==null){
lazyMan = new LazyMan01();
}
return lazyMan;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan01 instance = LazyMan01.getInstance();
}).start();
}
}
}
//双重检测锁 模式懒汉单例~线程安全 DCL 避免指令重排
public class LazyMan02 {
private LazyMan02(){
System.out.println(Thread.currentThread().getName() + "->创建");
}
//所以要避免指令重拍 添加volatile
private volatile static LazyMan02 lazyMan;
//不加双重校验在多线程下不安全
public static LazyMan02 getInstance(){
if(lazyMan==null){
synchronized (LazyMan02.class){
if(lazyMan==null){
lazyMan = new LazyMan02();//这行代码不是一个原子性操作
/**
* 三步:1分配内存空间;2执行构造方法,初始化对象;3把初始化对象指向分配的空间
* 期望指令为123
* 但是可能为132 线程A执行132
* 线程B //此时线程B来进行校验发现 lazyMan!=null 就返回一个空对象
*
* 所以要避免指令重拍 添加volatile
*/
}
}
}
return lazyMan;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan02 instance = LazyMan02.getInstance();
}).start();
}
}
}
//反射破坏单列模式
public class LazyMan03 {
private LazyMan03(){
}
private volatile static LazyMan03 lazyMan;
public static LazyMan03 getInstance(){
if(lazyMan==null){
synchronized (LazyMan03.class){
if(lazyMan==null){
lazyMan = new LazyMan03();
}
}
}
return lazyMan;
}
public static void main(String[] args) throws Exception {
LazyMan03 instance1 = LazyMan03.getInstance();//该方法调用一次私有构造方法 lazyMan会创建一个对象
Constructor<LazyMan03> declaredConstructor = LazyMan03.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan03 instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
//反射破坏单列模式
public class LazyMan04 {
private boolean boolVal = true;
private LazyMan04(){
synchronized (LazyMan04.class){
if(boolVal){
boolVal= false;
}else{
throw new RuntimeException("请不要试图用反射破坏单列异常");
}
}
}
private volatile static LazyMan04 lazyMan;
public static LazyMan04 getInstance(){
if(lazyMan==null){
synchronized (LazyMan04.class){
if(lazyMan==null){
lazyMan = new LazyMan04();
}
}
}
return lazyMan;
}
public static void main(String[] args) throws Exception {
Constructor<LazyMan03> declaredConstructor = LazyMan03.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
//根本没有使用私有构造方法创建 lazyMan会为null 所以不会抛异常
LazyMan03 instance1 = declaredConstructor.newInstance();
LazyMan03 instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
public class Singleton {
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
//enum 枚举也是一个class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance1 = EnumSingle.INSTANCE;
/**
* 运行抛异常 java.lang.NoSuchMethodException: com.companyname.single.EnumSingle.()
* 说明 没有无参构造方法
*/
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
//结果与预期相同 java.lang.IllegalArgumentException: Cannot reflectively create enum objects
}
}
总结
1 饿汉式
2 懒汉式
3 静态内部类
4 枚举模式
比较当前工作内存种的值和主内存中的值,如果这个值是期望的,那么执行操作!如果不是就一直循环
缺点
1循环会耗时
2一次性只能保证一个共享变量的原子性
3ABA问题
public class CASDemo {
public static void main(String[] args) {
//CAS compareAndSet:比较并交换
AtomicInteger atomicInteger = new AtomicInteger(2020);
//期望更新~如果我们期望的值达到了,那么就更新,否则就不更新CAS是CPU的并发原语;
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
}
}
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
...
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);//获取内存中的值
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); //内存操作,效率很高
return var5;
}
Unsafe java无法操作内存,Java可以调用c++ native c++可以操作内存,unsafe相当于Java的后门,可以通过这个类操作内存
public class CASDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//捣乱线程
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2021, 2020));
System.out.println(atomicInteger.get());
//期望线程
System.out.println(atomicInteger.compareAndSet(2020, 666));
System.out.println(atomicInteger.get());
}
}
Integer使用了对象缓存机制,默认范围-128~127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOf使用缓存,而new一定会创建新的对象分配新的内存空间
/**
* 1==是判断两个变量或实例是不是指向同一个内存空间,
* equals是判断两个变量或实例所指向的内存空间的值是不是相同
* 2==是指对内存地址进行比较 , equals()是对字符串的内容进行比较
* 3==指引用是否相同, equals()指的是值是否相同
*/
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = 1024;
Integer i2 = 1024;
Integer i3 = 24;
Integer i4 = 24;
System.out.println("i1==i2:"+(i1==i2)); //false
System.out.println("i1.equals(i2):"+i1.equals(i2));//true
System.out.println("--- -128~127之间的数 ----");
System.out.println("i3==i4:"+(i3==i4));//true
System.out.println("i3.equals(i4):"+i3.equals(i4));//true
}
}
原子引用 解决ABA问题,引入原子引用!对应的思想:乐观锁!
public class CASDemo2 {
public static void main(String[] args) {
AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<Integer>(27,1);
new Thread(()->{
System.out.println("a1=>"+stampedReference.getStamp());
//休眠一秒保证b线程获取到stampedReference.getStamp() 和 最开始是一直的都为1
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("a线程cas1:"+stampedReference.compareAndSet(27, 33, stampedReference.getStamp(), stampedReference.getStamp() + 1));
System.out.println("a2=>"+stampedReference.getStamp());
System.out.println("a线程cas2:"+stampedReference.compareAndSet(33, 27, stampedReference.getStamp(), stampedReference.getStamp() + 1));
System.out.println("a3=>"+stampedReference.getStamp());
},"a").start();
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println("b1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b线程cas1:"+stampedReference.compareAndSet(27, 66, stamp, stampedReference.getStamp() + 1));
System.out.println("b2=>"+stampedReference.getStamp());
},"b").start();
}
}
1公平锁、非公平锁
公平锁:非常公平,不能够插队,必须先来后到
非公平锁:非常不公平,可以插队(默认都是非公平)
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
2可重入锁
可从入锁(递归锁):
synchronized
public class LockDemo1 {
public static void main(String[] args) {
iPhone phone = new iPhone();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
}
class iPhone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName()+"=> sms");
call();
}
private synchronized void call() {
System.out.println(Thread.currentThread().getName()+"=> call");
}
}
public class LockDemo2 {
public static void main(String[] args) {
iPhone2 phone = new iPhone2();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
}
class iPhone2{
Lock lock = new ReentrantLock(); //lock锁必须配对,否则会死锁
public void sms(){
lock.lock();//第一把锁
try {
System.out.println(Thread.currentThread().getName()+"=> sms");
call();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private void call() {
lock.lock();//第一把锁
try {
System.out.println(Thread.currentThread().getName()+"=> call");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
public class SpinlockDemo3 {
AtomicReference<Thread> atomicReference = new AtomicReference();
public void mylock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"===> mylock");
//自旋锁
while (!atomicReference.compareAndSet(null,thread)){
}
}
public void myUnlock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"===> myUnlock");
atomicReference.compareAndSet(thread,null);
}
}
public class SpinlockDemo3Test {
public static void main(String[] args) throws InterruptedException {
SpinlockDemo3 lock = new SpinlockDemo3();
new Thread(()->{
lock.mylock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnlock();
}
},"A").start();
TimeUnit.SECONDS.sleep(2);
new Thread(()->{
lock.mylock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnlock();
}
},"B").start();
}
}
public class DeadLockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new MyThread(lockA,lockB),"T1").start();
new Thread(new MyThread(lockB,lockA),"T2").start();
}
}
class MyThread implements Runnable{
private String lockA;
private String lockB;
public MyThread(String lockA,String lockB){
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+" ->"+lockA+" get "+lockB+",lockB is locked");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+" ->"+lockB+" get "+lockA+",lockA is locked");
}
}
}
}