多线程高并发笔记
1.进程,线程
进程:程序的一次执行 QQ,动态概念
线程:进程里最小的执行单元叫线程,一个程序里线程不同的执行路径
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/4 23:07
*/
public class T01_WhatsThread {
private static class T1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1");
}
}
}
public static void main(String[] args) {
new T1().start();//调度新的线程进程执行
//new T1().run(); 为执行类的方法
for (int i = 0; i < 10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
}
2.创建线程的方式
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/4 23:29
*/
public class T02_HowToCreateThread {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread的run方法执行了");
}
}
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable的run方法执行了");
}
}
public static void main(String[] args) {
new MyThread().start();
new
Thread(new MyRunnable()).start();
new
Thread(() -> {
System.out.println("lambda多线程的run方法执行了");
}).start();
}
}
//启动线程的方式:1.继承Thread 2.实现Runnable 3.线程池起线程Executors.newCachedThread(内部用的前两种)
3.线程基本方法
3.1sleep, Thread.sleep(500);
当前线程暂停一段时间让给其他线程去执行,睡眠完回到就绪队列
3.2yield, Thread.yield();
非常谦让的退出一下,进入等待队列
3.3join t1.join();
把其他线程加入此线程,等加入的执行完在执行当前线程
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/4 23:55
*/
public class T03_Sleep_Yield_Join {
public static void main(String[] args) {
// testSleep();
// testYield();
testJoin();
}
static void testSleep() {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
static void testYield() {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("y" + i);
if (i % 10 == 0) {
Thread.yield();
}
}
}).start();
}
static void testJoin() {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("t1A" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("t2B" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t2");
t1.start();
t2.start();
}
}
4.线程的状态
绿色块6个状态
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:00
*/
public class T03_ThreadState {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println(this.getState());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getState());
t.start();
try {
//确保线程执行完再执行后面的代码
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getState());
}
}
5.synchronized
5.1基本用法
锁定对象不能为String常量 Integer Long等基本数据类型,String所有引用用的一个,会出现异常,
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:17
*/
public class T04_Synchronized {
private int count = 10;
private Object o = new Object();
public void m() {
synchronized (o) {
count--;
System.out.println(Thread.currentThread().getName() + " count=" + count);
}
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:24
*/
public class T05_SynchronizedThis {
private int count = 10;
public void m() {
//等价与synchronized方法
synchronized (this) {
count--;
System.out.println(Thread.currentThread().getName() + "count =" + count);
}
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:27
*/
public class T06_SynchronizedMathod {
private int count = 10;
public synchronized void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count =" + count);
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:30
*/
public class T07_SynchronizedClass {
private static int count = 10;
//等同于synchronized(T07_SynchronizedClass.class);
public synchronized static void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
public static void mm() {
synchronized (T07_SynchronizedClass.class) {
count--;
}
}
}
5.2非synchronized方法可以跟synchronized方法同时执行,至少两个线程进行验证
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 10:44
*/
public class T09_SynchronizedAndNotSyn {
public synchronized void m1() {
System.out.println(Thread.currentThread().getName() + "m1 start...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m1 end");
}
public void m2() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m2");
}
public static void main(String[] args) {
T09_SynchronizedAndNotSyn t = new T09_SynchronizedAndNotSyn();
//验证非synchronized方法会跟非syn方法同时执行,两个线程进行执行,输出结果可以看到
new Thread(t::m1, "t1").start();
new Thread(t::m2, "t2").start();
}
}
案列,读到中间结果
/**
* 面试题:模拟银行账户
* 对业务写方法加锁
* 对业务读方法不加锁
* 这样行不行?
*
* 容易产生脏读问题(dirtyRead)
*/
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:04
*/
public class Account {
String name;
double balance;
public synchronized void set(String name, double balance) {
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public double get(String name) {
return this.balance;
}
public static void main(String[] args) {
Account a = new Account();
new Thread(() -> {
a.set("张三", 100);
}, "set线程").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(a.get("张三"));
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(a.get("张三"));
}
}
5.3可重入性
Synchronized是可重入锁,也就是两个方法都进行了synchronized加锁,一个掉另一个,同一个线程内感知倒已经获取到锁,则可以进行调用,否则会导致死锁
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:29
*/
public class T10_CanRepeatSynchronized {
public synchronized void m1(){
System.out.println("m1 start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
m2();
System.out.println("m1 end");
}
public synchronized void m2(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2");
}
public static void main(String[] args) {
T10_CanRepeatSynchronized t=new T10_CanRepeatSynchronized();
new Thread(t::m1).start();
}
}
输出结果
m1 start
m2
m1 end
子类的synchronized可以调用父类的,否则会出现死锁
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:39
*/
public class T11_CanRepeatSynchronized02 {
public synchronized void m() {
System.out.println("m start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m end");
}
public static void main(String[] args) {
new T11_Child().m();
}
}
class T11_Child extends T11_CanRepeatSynchronized02 {
@Override
public synchronized void m() {
System.out.println("child m start");
super.m();
System.out.println("child m end");
}
}
输出结果
child m start
m start
m end
child m end
5.4异常会导致锁释放,可能会导致程序乱入
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:53
*/
public class T12_ExceptionOutSynch {
int count = 0;
public synchronized void m() {
System.out.println(Thread.currentThread().getName() + "start");
while (true) {
count++;
System.out.println(Thread.currentThread().getName() + "count=" + count);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 5) {
int i = 1 / 0;
System.out.println("出现异常了");
}
}
}
public static void main(String[] args) {
T12_ExceptionOutSynch t = new T12_ExceptionOutSynch();
Runnable runnable = new Runnable() {
@Override
public void run() {
t.m();
}
};
new Thread(runnable).start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(t::m).start();
}
}
发生异常原本没有机会执行的线程得到执行机会,会乱入执行
5.4底层实现原理
JDK1.5之前是重量级的-OS锁
之后开始优化
1)刚开始是无锁状态
2)当有线程进行访问,在对象头的两位进行记录,markword记录线程ID,也就是偏向锁,此线程可以直接进行下一次调用
3)当有线程进行争用的时候,升级为自旋锁,争用线程不会立即进入就绪队列,而是会while 等待10次,10次之后进入下一阶段(占用cpu,不访问操作系统,用户态非内核态)
4)升级为重量级锁-OS,线程进入等待序列,不在占用cpu
执行时间长选系统锁,执行时间短,线程不是很多的情况下选择自旋锁。
6.volatile
作用:保证线程可见性;禁止指令重排序
6.1保证线程可见性
-MESI
-缓存一致性协议,多个cpu之间
(不同线程会对堆内存的变量复制到本地进行操作,操作完然后写入,所以即使操作完写入其他线程也无法感知到)
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/9 0:24
*/
public class T13_Volatile {
//不加volatile,当另一个线程修改字段值,主线程无法感知到
/*volatile*/ boolean running=true;
void m(){
System.out.println("m start");
while(running){
}
System.out.println("m end");
}
public static void main(String[] args) {
T13_Volatile t=new T13_Volatile();
new Thread(t::m).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.running=false;
}
}
6.2禁止指令重排序
Cpu执行指令会进行同时执行,存在顺序调换的可能
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/9 1:02
*/
public class T14_VolatileSingle {
private T14_VolatileSingle() {
}
private static volatile T14_VolatileSingle INSTANCE;
public static T14_VolatileSingle getInstance() {
if (INSTANCE == null) {
//DCL双重检查
synchronized (T14_VolatileSingle.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new T14_VolatileSingle();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
new Thread(() -> {
System.out.println(T14_VolatileSingle.getInstance().hashCode());
}).start();
}
}
}
添加volatile的原因,INSTANCE = new T14_VolatileSingle();,创建对象的过程分为三步
第一步:给对象申请内存,并赋为初始值
第二步:给对象将值赋为真正的值
第三步:将变量指向对象
第三步跟第二步发生指令重排序,此时变量指向的对象已经不是null,但是也不是真正的值,获取此数据直接去使用会有异常,是不正确的。
Volatile会禁止指令重排序,以下程序有volatile没有synchronized也是不正确的,修改后其他线程可见,但是++内部会分很多步执行,其他线程会对相同值进行++后赋值,会比实际的小
Volatile不能替代synchronized,只是保证可见性package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
/**
* @author hanyong
* @date 2020/9/9 22:33
*/
public class T15_VolatileCanNotReplaceSyn {
volatile int count = 0;
synchronized void m() {
for (int i = 0; i < 10000; i++) {
count++;
}
}
public static void main(String[] args) {
T15_VolatileCanNotReplaceSyn t = new T15_VolatileCanNotReplaceSyn();
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
7.锁其他点
7.1细化锁,粗化锁
细化尽可能的锁最少的代码,粗化锁当方法征用频繁的时候粗胡下
package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
/**
* 细化锁
*
* @author hanyong
* @date 2020/9/9 22:53
*/
public class T16_FineLock {
volatile int count = 0;
void m() {
try {
//业务逻辑
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
count++;
}
try {
//业务逻辑
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
T16_FineLock t = new T16_FineLock();
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
7.2锁同一对象
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/9 23:04
*/
public class T17_SynSameObject {
final Object o = new Object();//加final防止被重新赋值
void m() {
synchronized (o) {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
T17_SynSameObject t = new T17_SynSameObject();
new Thread(t::m, "thread1").start();
new Thread(t::m, "thread2").start();
// t.o = new Object();//注释掉后thread2不会执行,此处对象变成另一个对象,先执行的线程锁不住第二个线程
}
}
8.CAS
8.1AtomicInteger使用案列
package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author hanyong
* @date 2020/9/9 23:30
*/
public class T18_AtomicInteger {
AtomicInteger count=new AtomicInteger(0);
void m() {
for (int i = 0; i < 1000; i++) {
count.incrementAndGet();
}
}
public static void main(String[] args) {
T18_AtomicInteger t = new T18_AtomicInteger();
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
8.2原理
内部调用Unsafe的getAndAddInt方法
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;
}
cas(v,excepted,NewValue); v为之前获得值,e为期待值,n为要设定的新值
if(v==e)
v=new
否则重试。Cas是cpu原语级别,执行过程不会被打断,也就是不怕其他线程打断出错
ABA问题,解决思路加version
8.3atomic synchronized Longadder性能大比拼
package com.hy.mashibing2.knowledge;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
/**
* @author hanyong
* @date 2020/9/10 23:31
*/
public class T19_AtomicvsSynvsLongAdder {
static AtomicInteger count1 = new AtomicInteger(0);
static long count2 = 0L;
static LongAdder count3 = new LongAdder();
public static void main(String[] args) {
Thread[] threads = new Thread[1000];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 10000; k++) {
count1.incrementAndGet();
}
});
}
long atomiStartTime = System.currentTimeMillis();
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long atomEndTime = System.currentTimeMillis();
System.out.println("AtomicInteger" + count1.get() + "耗时:" + (atomEndTime - atomiStartTime));
final Object o = new Object();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int k = 0; k < 10000; k++) {
synchronized (o) {
count2++;
}
}
}
});
}
long longStartTime = System.currentTimeMillis();
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long longEndTime = System.currentTimeMillis();
System.out.println("synch" + count2 + "耗时:" + (longEndTime - longStartTime));
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 10000; k++) {
count3.increment();
}
});
}
long longAddStartTime = System.currentTimeMillis();
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long longAddEndTime = System.currentTimeMillis();
System.out.println("LongAdd" + count3.longValue() + "耗时:" + (longAddEndTime - longAddStartTime));
}
}
输出结果:
AtomicInteger10000000耗时:203
synch10000000耗时:549
LongAdd10000000耗时:135
LongAdder线程多时效率最高,原因LongAdder内部会有一个数组,将数字放到数组中,不同部分线程对数组的某个索引值进行递增,最终对数组所有元素进行递增,内部实现也是CAS所以较快。
250个线程对第一个进行递增,250线程对第二个进行递增,。。。最终进行相加得到结果
9.新型锁
9.1reentrantLock可重入性
可重入性,不同线程存在竞争,但是相同线程执行一个方法,当方法内部调用其他加锁方法时,当synch锁的是同一个对象就可以进行调用。可重入性
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/11 0:31
*/
public class T20_ReentrantLock1 {
synchronized void m1() {
for (int i = 0; i < 10; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
if(i==2){
m2();
}
}
}
synchronized void m2() {
System.out.println("m2执行了");
}
public static void main(String[] args) {
T20_ReentrantLock1 t = new T20_ReentrantLock1();
new Thread(t::m1).start();
// new Thread(t::m2).start();
}
}
9.2reentrantLock基本用法
作用同synchronized。Try,finally使用。使用前lock,finally里面unlock掉
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 18:57
*/
public class T21_ReentrantLock2 {
ReentrantLock
lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println("m" + i);
}
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
void m2() {
try {
lock.lock();
System.out.println("m2执行了");
} finally {
lock.unlock();
}
}
public static
void main(String[] args) {
T21_ReentrantLock2
t = new T21_ReentrantLock2();
new Thread(t::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
new Thread(t::m2).start();
}
}
9.3reentrantLock lock.tryLock案例
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 21:24
*/
public class T23_ReentrantLock3
{
ReentrantLock lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 3; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 使用tryLock进行尝试锁定,无论锁定与否,方法都会继续执行
* 可以根据tryLock的返回值来判断是否锁定
* 也可指定tryLock的时间
*/
void m2() {
boolean locked = false;
try {
//5秒钟之内一直去获得锁,如果获得锁,locked就为true,
locked = lock.tryLock(3, TimeUnit.SECONDS);
System.out.println("m2方法执行了"+locked);
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
if (locked) {
lock.unlock();
}
}
}
public static void main(String[] args) {
T23_ReentrantLock3 t=new T23_ReentrantLock3();
new
Thread(t::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
new Thread(t::m2).start();
}
}
9.4 reentrantLock lock.lockInterruptibly可被打断,执行catch块的方法
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 23:41
*/
public class T24_ReentrantLock4
{
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread t1=new Thread(()->{
try {
lock.lock();
System.out.println("线程1start");
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
System.out.println("线程1end");
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
lock.unlock();
}
},"线程1");
Thread t2=new Thread(()->{
try{
lock.lockInterruptibly();
System.out.println("线程2执行开始");
TimeUnit.SECONDS.sleep(5);
System.out.println("线程2执行结束");
} catch (InterruptedException
e) {
System.out.println("m2被打断"+e.getMessage());
e.printStackTrace();
}finally {
lock.unlock();
}
},"线程2");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
t2.start();
t2.interrupt();
}
}
9.5reentrantLock公平锁
一个线程执行完,另一个线程再执行,新加过来的线程进入等待队列,有序队列,排队执行。不会乱序争抢
package com.hy.mashibing2.knowledge;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/13 0:09
*/
public class T25_ReentrantLock5
extends Thread {
//公平锁
private static ReentrantLock
lock = new ReentrantLock(true);
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得锁");
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
T25_ReentrantLock5 t = new T25_ReentrantLock5();
Thread thread1 = new Thread(t, "线程1");
Thread thread2 = new Thread(t, "线程2");
thread1.start();
thread2.start();
}
}
打印结果
线程2获得锁
线程1获得锁
线程2获得锁
线程1获得锁
9.6CountDownLatch
package com.hy.mashibing2.knowledge;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch倒数门闩
*
* @author hanyong
* @date 2020/9/14 21:45
*/
public class T26_CountDownLatch1 {
public static void main(String[] args) {
}
private static void
usingCountDownLatch() {
Thread[] threads = new Thread[100];
CountDownLatch latch = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
int
result = 0;
for
(int j = 0; j < 10000; j++) {
result += j;
latch.countDown();
}
});
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
try {
latch.await(); //所有的线程latch.countDown();执行完,门闩打开执行后面的代码
} catch (InterruptedException
e) {
e.printStackTrace();
}
System.out.println("end
latch");
}
private static void
usingJoin() {
Thread[] threads = new Thread[100];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
int
result = 0;
for
(int j = 0; j < 10000; j++) {
result += j;
}
});
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
}
}
9.7CyclicBarrier 栅栏,满后执行
package com.hy.mashibing2.knowledge;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
*
* CyclicBarrier栅栏,满了之后做后续动作
* @author hanyong
* @date 2020/9/14 23:29
*/
public class T27_CyclicBarrier {
public static void main(String[] args) {
// CyclicBarrier barrier =
new CyclicBarrier(20);
CyclicBarrier barrier = new CyclicBarrier(20,()->{
System.out.println("lamda满人发车");
});
/* CyclicBarrier
barrier = new CyclicBarrier(20, new Runnable() {
@Override
public void run() {
System.out.println("人满发车");
}
});*/
Thread[] threads = new Thread[100];
for (int i = 0; i < threads.length; i++) {
new
Thread(() -> {
try
{
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
9.8Phaser阶段锁
所有线程执行完当前阶段再开始执行下一阶段
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister();
package com.hy.mashibing2.knowledge;
import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/15 0:19
*/
public class T28_Phaser1 {
static Random r = new Random();
static Phaser phaser = new MarriagePhaser();
static void sleep(int nums) {
try {
TimeUnit.MILLISECONDS.sleep(nums);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
phaser.bulkRegister(7);
for (int i = 0; i < 5; i++) {
new Thread(new Persion("p" + i)).start();
}
new
Thread(new Persion("新郎")).start();
new
Thread(new Persion("新娘")).start();
}
static class MarriagePhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase) {
case 0:
System.out.println("所有人到齐了!" + registeredParties);
System.out.println();
return false;
case 1:
System.out.println("所有人吃完了!" + registeredParties);
System.out.println();
return false;
case 2:
System.out.println("所有人离开了!" + registeredParties);
System.out.println();
return false;
case 3:
System.out.println("婚礼结束!新娘新郎抱抱" + registeredParties);
return true;
default:
return true;
}
}
}
static class Persion implements Runnable {
String name;
public Persion(String name) {
this.name = name;
}
void arrive() {
sleep(1000);
System.out.printf("%s 到达现场! \n", name);
phaser.arriveAndAwaitAdvance();
}
void eat() {
sleep(1000);
System.out.printf("%s 吃完!\n", name);
phaser.arriveAndAwaitAdvance();
}
void leave() {
sleep(1000);
System.out.printf("%s 离开!\n", name);
phaser.arriveAndAwaitAdvance();
}
void hug() {
if (name.equals("新郎") || name.equals("新娘")) {
sleep(1000);
System.out.printf("%s 洞房!\n", name);
phaser.arriveAndAwaitAdvance();
} else {
phaser.arriveAndDeregister();
}
}
@Override
public void run() {
arrive();
eat();
leave();
hug();
}
}
}
9.9读写锁
static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
readLock为共享锁,读线程可以同时执行,writeLock为排他锁,独占执行
案例如下
package com.hy.mashibing2.knowledge;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author hanyong
* @date 2020/9/15 23:20
*/
public class T29_ReadWriterLock
{
static int value;
static ReentrantLock
lock = new ReentrantLock();
static ReentrantReadWriteLock
readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writerLock = readWriteLock.writeLock();
public static void read(Lock lock) {
try {
lock.lock();
sleep(1);
System.out.println(Thread.currentThread().getName() + "读完了");
} finally {
lock.unlock();
}
}
public static void writer(Lock lock, int v) {
try {
lock.lock();
sleep(1);
value = v;
System.out.println(Thread.currentThread().getName() + "写完了");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
//创建10个线程读
for (int i = 0; i < 10; i++) {
new Thread(() -> {
read(readLock);
}, "读线程" + i).start();
}
//创建2个线程写
for (int i = 0; i < 2; i++) {
new
Thread(() -> {
writer(writerLock,
new Random().nextInt());
}, "写线程" + i).start();
}
}
static void sleep(int time) {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
}
9.10semaphore信号量
做限流
package com.hy.mashibing2.knowledge;
import java.util.concurrent.Semaphore;
/**
* @author hanyong
* @date 2020/9/16 22:09
*/
public class T30_Semaphore {
public static void main(String[] args) {
//1表示同时只能有一个线程执行
//Semaphore
semaphore=new Semaphore(1);
Semaphore semaphore=new Semaphore(1,true);//公平锁,队列,线程排队
new
Thread(()->{
try
{
semaphore.acquire();//阻塞获得,后为0
System.out.println("T1
running...");
Thread.sleep(200);
System.out.println("T1
running...");
} catch
(InterruptedException e)
{
e.printStackTrace();
}finally {
semaphore.release();//释放,后为1
}
},"t1").start();
new
Thread(()->{
try
{
semaphore.acquire();
System.out.println("T2 running");
Thread.sleep(200);
System.out.println("T2 running");
} catch
(InterruptedException e)
{
e.printStackTrace();
}finally
{
semaphore.release();
}
},"t2").start();
}
}
9.11Exchanger交换
*/
public class T31_Exchange {
static Exchanger<String> exchanger = new Exchanger();
public static void main(String[] args) {
new
Thread(() -> {
String
s = "t1";
try
{
s= exchanger.exchange(s);//双人游戏交换装备
} catch
(InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + s);
}, "线程1").start();
new
Thread(() -> {
String
s = "t2";
try
{
s= exchanger.exchange(s);
} catch
(InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + s);
}, "线程2").start();
}
}
打印结果
线程1t2
线程2t1
9.12LockSupport
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
*
* LockSupport.park();不用加锁可以暂停线程
* LockSupport.unpark(t);可以恢复park的线程继续执行
*
LockSupport.unpark(t);可以优先于LockSupport.park();执行,这样park的时候可以不用park
*
* 内部实现类似于维护一个count,park变为0,unpark变为1,变为1线程继续执行,之前已经为1则park不停继续执行,再次变为0就停
* @author hanyong
* @date 2020/9/16 23:49
*/
public class T32_LockSupport {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for
(int i = 0; i < 10; i++) {
System.out.println(i);
if
(i == 5) {
LockSupport.park();
}
try
{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
LockSupport.unpark(t);
/*try {
TimeUnit.SECONDS.sleep(8);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("主线程睡了8秒了");
LockSupport.unpark(t);*/
}
}
1.进程,线程
进程:程序的一次执行 QQ,动态概念
线程:进程里最小的执行单元叫线程,一个程序里线程不同的执行路径
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/4 23:07
*/
public class T01_WhatsThread {
private static class T1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1");
}
}
}
public static void main(String[] args) {
new T1().start();//调度新的线程进程执行
//new T1().run(); 为执行类的方法
for (int i = 0; i < 10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
}
2.创建线程的方式
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/4 23:29
*/
public class T02_HowToCreateThread {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread的run方法执行了");
}
}
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable的run方法执行了");
}
}
public static void main(String[] args) {
new MyThread().start();
new
Thread(new MyRunnable()).start();
new
Thread(() -> {
System.out.println("lambda多线程的run方法执行了");
}).start();
}
}
//启动线程的方式:1.继承Thread 2.实现Runnable 3.线程池起线程Executors.newCachedThread(内部用的前两种)
3.线程基本方法
3.1sleep, Thread.sleep(500);
当前线程暂停一段时间让给其他线程去执行,睡眠完回到就绪队列
3.2yield, Thread.yield();
非常谦让的退出一下,进入等待队列
3.3join t1.join();
把其他线程加入此线程,等加入的执行完在执行当前线程
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/4 23:55
*/
public class T03_Sleep_Yield_Join {
public static void main(String[] args) {
// testSleep();
// testYield();
testJoin();
}
static void testSleep() {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
static void testYield() {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("y" + i);
if (i % 10 == 0) {
Thread.yield();
}
}
}).start();
}
static void testJoin() {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("t1A" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("t2B" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t2");
t1.start();
t2.start();
}
}
4.线程的状态
绿色块6个状态
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:00
*/
public class T03_ThreadState {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println(this.getState());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getState());
t.start();
try {
//确保线程执行完再执行后面的代码
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getState());
}
}
5.synchronized
5.1基本用法
锁定对象不能为String常量 Integer Long等基本数据类型,String所有引用用的一个,会出现异常,
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:17
*/
public class T04_Synchronized {
private int count = 10;
private Object o = new Object();
public void m() {
synchronized (o) {
count--;
System.out.println(Thread.currentThread().getName() + " count=" + count);
}
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:24
*/
public class T05_SynchronizedThis {
private int count = 10;
public void m() {
//等价与synchronized方法
synchronized (this) {
count--;
System.out.println(Thread.currentThread().getName() + "count =" + count);
}
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:27
*/
public class T06_SynchronizedMathod {
private int count = 10;
public synchronized void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count =" + count);
}
}
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 0:30
*/
public class T07_SynchronizedClass {
private static int count = 10;
//等同于synchronized(T07_SynchronizedClass.class);
public synchronized static void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
public static void mm() {
synchronized (T07_SynchronizedClass.class) {
count--;
}
}
}
5.2非synchronized方法可以跟synchronized方法同时执行,至少两个线程进行验证
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/6 10:44
*/
public class T09_SynchronizedAndNotSyn {
public synchronized void m1() {
System.out.println(Thread.currentThread().getName() + "m1 start...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m1 end");
}
public void m2() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m2");
}
public static void main(String[] args) {
T09_SynchronizedAndNotSyn t = new T09_SynchronizedAndNotSyn();
//验证非synchronized方法会跟非syn方法同时执行,两个线程进行执行,输出结果可以看到
new Thread(t::m1, "t1").start();
new Thread(t::m2, "t2").start();
}
}
案列,读到中间结果
/**
* 面试题:模拟银行账户
* 对业务写方法加锁
* 对业务读方法不加锁
* 这样行不行?
*
* 容易产生脏读问题(dirtyRead)
*/
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:04
*/
public class Account {
String name;
double balance;
public synchronized void set(String name, double balance) {
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public double get(String name) {
return this.balance;
}
public static void main(String[] args) {
Account a = new Account();
new Thread(() -> {
a.set("张三", 100);
}, "set线程").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(a.get("张三"));
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(a.get("张三"));
}
}
5.3可重入性
Synchronized是可重入锁,也就是两个方法都进行了synchronized加锁,一个掉另一个,同一个线程内感知倒已经获取到锁,则可以进行调用,否则会导致死锁
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:29
*/
public class T10_CanRepeatSynchronized {
public synchronized void m1(){
System.out.println("m1 start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
m2();
System.out.println("m1 end");
}
public synchronized void m2(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2");
}
public static void main(String[] args) {
T10_CanRepeatSynchronized t=new T10_CanRepeatSynchronized();
new Thread(t::m1).start();
}
}
输出结果
m1 start
m2
m1 end
子类的synchronized可以调用父类的,否则会出现死锁
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:39
*/
public class T11_CanRepeatSynchronized02 {
public synchronized void m() {
System.out.println("m start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m end");
}
public static void main(String[] args) {
new T11_Child().m();
}
}
class T11_Child extends T11_CanRepeatSynchronized02 {
@Override
public synchronized void m() {
System.out.println("child m start");
super.m();
System.out.println("child m end");
}
}
输出结果
child m start
m start
m end
child m end
5.4异常会导致锁释放,可能会导致程序乱入
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/6 11:53
*/
public class T12_ExceptionOutSynch {
int count = 0;
public synchronized void m() {
System.out.println(Thread.currentThread().getName() + "start");
while (true) {
count++;
System.out.println(Thread.currentThread().getName() + "count=" + count);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 5) {
int i = 1 / 0;
System.out.println("出现异常了");
}
}
}
public static void main(String[] args) {
T12_ExceptionOutSynch t = new T12_ExceptionOutSynch();
Runnable runnable = new Runnable() {
@Override
public void run() {
t.m();
}
};
new Thread(runnable).start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(t::m).start();
}
}
发生异常原本没有机会执行的线程得到执行机会,会乱入执行
5.4底层实现原理
JDK1.5之前是重量级的-OS锁
之后开始优化
1)刚开始是无锁状态
2)当有线程进行访问,在对象头的两位进行记录,markword记录线程ID,也就是偏向锁,此线程可以直接进行下一次调用
3)当有线程进行争用的时候,升级为自旋锁,争用线程不会立即进入就绪队列,而是会while 等待10次,10次之后进入下一阶段(占用cpu,不访问操作系统,用户态非内核态)
4)升级为重量级锁-OS,线程进入等待序列,不在占用cpu
执行时间长选系统锁,执行时间短,线程不是很多的情况下选择自旋锁。
6.volatile
作用:保证线程可见性;禁止指令重排序
6.1保证线程可见性
-MESI
-缓存一致性协议,多个cpu之间
(不同线程会对堆内存的变量复制到本地进行操作,操作完然后写入,所以即使操作完写入其他线程也无法感知到)
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/9 0:24
*/
public class T13_Volatile {
//不加volatile,当另一个线程修改字段值,主线程无法感知到
/*volatile*/ boolean running=true;
void m(){
System.out.println("m start");
while(running){
}
System.out.println("m end");
}
public static void main(String[] args) {
T13_Volatile t=new T13_Volatile();
new Thread(t::m).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.running=false;
}
}
6.2禁止指令重排序
Cpu执行指令会进行同时执行,存在顺序调换的可能
package com.hy.mashibing2.knowledge;
/**
* @author hanyong
* @date 2020/9/9 1:02
*/
public class T14_VolatileSingle {
private T14_VolatileSingle() {
}
private static volatile T14_VolatileSingle INSTANCE;
public static T14_VolatileSingle getInstance() {
if (INSTANCE == null) {
//DCL双重检查
synchronized (T14_VolatileSingle.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new T14_VolatileSingle();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
new Thread(() -> {
System.out.println(T14_VolatileSingle.getInstance().hashCode());
}).start();
}
}
}
添加volatile的原因,INSTANCE = new T14_VolatileSingle();,创建对象的过程分为三步
第一步:给对象申请内存,并赋为初始值
第二步:给对象将值赋为真正的值
第三步:将变量指向对象
第三步跟第二步发生指令重排序,此时变量指向的对象已经不是null,但是也不是真正的值,获取此数据直接去使用会有异常,是不正确的。
Volatile会禁止指令重排序,以下程序有volatile没有synchronized也是不正确的,修改后其他线程可见,但是++内部会分很多步执行,其他线程会对相同值进行++后赋值,会比实际的小
Volatile不能替代synchronized,只是保证可见性package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
/**
* @author hanyong
* @date 2020/9/9 22:33
*/
public class T15_VolatileCanNotReplaceSyn {
volatile int count = 0;
synchronized void m() {
for (int i = 0; i < 10000; i++) {
count++;
}
}
public static void main(String[] args) {
T15_VolatileCanNotReplaceSyn t = new T15_VolatileCanNotReplaceSyn();
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
7.锁其他点
7.1细化锁,粗化锁
细化尽可能的锁最少的代码,粗化锁当方法征用频繁的时候粗胡下
package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
/**
* 细化锁
*
* @author hanyong
* @date 2020/9/9 22:53
*/
public class T16_FineLock {
volatile int count = 0;
void m() {
try {
//业务逻辑
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
count++;
}
try {
//业务逻辑
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
T16_FineLock t = new T16_FineLock();
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
7.2锁同一对象
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/9 23:04
*/
public class T17_SynSameObject {
final Object o = new Object();//加final防止被重新赋值
void m() {
synchronized (o) {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
T17_SynSameObject t = new T17_SynSameObject();
new Thread(t::m, "thread1").start();
new Thread(t::m, "thread2").start();
// t.o = new Object();//注释掉后thread2不会执行,此处对象变成另一个对象,先执行的线程锁不住第二个线程
}
}
8.CAS
8.1AtomicInteger使用案列
package com.hy.mashibing2.knowledge;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author hanyong
* @date 2020/9/9 23:30
*/
public class T18_AtomicInteger {
AtomicInteger count=new AtomicInteger(0);
void m() {
for (int i = 0; i < 1000; i++) {
count.incrementAndGet();
}
}
public static void main(String[] args) {
T18_AtomicInteger t = new T18_AtomicInteger();
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
8.2原理
内部调用Unsafe的getAndAddInt方法
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;
}
cas(v,excepted,NewValue); v为之前获得值,e为期待值,n为要设定的新值
if(v==e)
v=new
否则重试。Cas是cpu原语级别,执行过程不会被打断,也就是不怕其他线程打断出错
ABA问题,解决思路加version
8.3atomic synchronized Longadder性能大比拼
package com.hy.mashibing2.knowledge;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
/**
* @author hanyong
* @date 2020/9/10 23:31
*/
public class T19_AtomicvsSynvsLongAdder {
static AtomicInteger count1 = new AtomicInteger(0);
static long count2 = 0L;
static LongAdder count3 = new LongAdder();
public static void main(String[] args) {
Thread[] threads = new Thread[1000];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 10000; k++) {
count1.incrementAndGet();
}
});
}
long atomiStartTime = System.currentTimeMillis();
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long atomEndTime = System.currentTimeMillis();
System.out.println("AtomicInteger" + count1.get() + "耗时:" + (atomEndTime - atomiStartTime));
final Object o = new Object();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int k = 0; k < 10000; k++) {
synchronized (o) {
count2++;
}
}
}
});
}
long longStartTime = System.currentTimeMillis();
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long longEndTime = System.currentTimeMillis();
System.out.println("synch" + count2 + "耗时:" + (longEndTime - longStartTime));
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 10000; k++) {
count3.increment();
}
});
}
long longAddStartTime = System.currentTimeMillis();
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long longAddEndTime = System.currentTimeMillis();
System.out.println("LongAdd" + count3.longValue() + "耗时:" + (longAddEndTime - longAddStartTime));
}
}
输出结果:
AtomicInteger10000000耗时:203
synch10000000耗时:549
LongAdd10000000耗时:135
LongAdder线程多时效率最高,原因LongAdder内部会有一个数组,将数字放到数组中,不同部分线程对数组的某个索引值进行递增,最终对数组所有元素进行递增,内部实现也是CAS所以较快。
250个线程对第一个进行递增,250线程对第二个进行递增,。。。最终进行相加得到结果
9.新型锁
9.1reentrantLock可重入性
可重入性,不同线程存在竞争,但是相同线程执行一个方法,当方法内部调用其他加锁方法时,当synch锁的是同一个对象就可以进行调用。可重入性
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/11 0:31
*/
public class T20_ReentrantLock1 {
synchronized void m1() {
for (int i = 0; i < 10; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
if(i==2){
m2();
}
}
}
synchronized void m2() {
System.out.println("m2执行了");
}
public static void main(String[] args) {
T20_ReentrantLock1 t = new T20_ReentrantLock1();
new Thread(t::m1).start();
// new Thread(t::m2).start();
}
}
9.2reentrantLock基本用法
作用同synchronized。Try,finally使用。使用前lock,finally里面unlock掉
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 18:57
*/
public class T21_ReentrantLock2 {
ReentrantLock
lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println("m" + i);
}
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
void m2() {
try {
lock.lock();
System.out.println("m2执行了");
} finally {
lock.unlock();
}
}
public static
void main(String[] args) {
T21_ReentrantLock2
t = new T21_ReentrantLock2();
new Thread(t::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
new Thread(t::m2).start();
}
}
9.3reentrantLock lock.tryLock案例
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 21:24
*/
public class T23_ReentrantLock3
{
ReentrantLock lock = new ReentrantLock();
void m1() {
try {
lock.lock();
for (int i = 0; i < 3; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 使用tryLock进行尝试锁定,无论锁定与否,方法都会继续执行
* 可以根据tryLock的返回值来判断是否锁定
* 也可指定tryLock的时间
*/
void m2() {
boolean locked = false;
try {
//5秒钟之内一直去获得锁,如果获得锁,locked就为true,
locked = lock.tryLock(3, TimeUnit.SECONDS);
System.out.println("m2方法执行了"+locked);
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
if (locked) {
lock.unlock();
}
}
}
public static void main(String[] args) {
T23_ReentrantLock3 t=new T23_ReentrantLock3();
new
Thread(t::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
new Thread(t::m2).start();
}
}
9.4 reentrantLock lock.lockInterruptibly可被打断,执行catch块的方法
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/12 23:41
*/
public class T24_ReentrantLock4
{
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread t1=new Thread(()->{
try {
lock.lock();
System.out.println("线程1start");
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
System.out.println("线程1end");
} catch (InterruptedException
e) {
e.printStackTrace();
} finally {
lock.unlock();
}
},"线程1");
Thread t2=new Thread(()->{
try{
lock.lockInterruptibly();
System.out.println("线程2执行开始");
TimeUnit.SECONDS.sleep(5);
System.out.println("线程2执行结束");
} catch (InterruptedException
e) {
System.out.println("m2被打断"+e.getMessage());
e.printStackTrace();
}finally {
lock.unlock();
}
},"线程2");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException
e) {
e.printStackTrace();
}
t2.start();
t2.interrupt();
}
}
9.5reentrantLock公平锁
一个线程执行完,另一个线程再执行,新加过来的线程进入等待队列,有序队列,排队执行。不会乱序争抢
package com.hy.mashibing2.knowledge;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hanyong
* @date 2020/9/13 0:09
*/
public class T25_ReentrantLock5
extends Thread {
//公平锁
private static ReentrantLock
lock = new ReentrantLock(true);
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得锁");
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
T25_ReentrantLock5 t = new T25_ReentrantLock5();
Thread thread1 = new Thread(t, "线程1");
Thread thread2 = new Thread(t, "线程2");
thread1.start();
thread2.start();
}
}
打印结果
线程2获得锁
线程1获得锁
线程2获得锁
线程1获得锁
9.6CountDownLatch
package com.hy.mashibing2.knowledge;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch倒数门闩
*
* @author hanyong
* @date 2020/9/14 21:45
*/
public class T26_CountDownLatch1 {
public static void main(String[] args) {
}
private static void
usingCountDownLatch() {
Thread[] threads = new Thread[100];
CountDownLatch latch = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
int
result = 0;
for
(int j = 0; j < 10000; j++) {
result += j;
latch.countDown();
}
});
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
try {
latch.await(); //所有的线程latch.countDown();执行完,门闩打开执行后面的代码
} catch (InterruptedException
e) {
e.printStackTrace();
}
System.out.println("end
latch");
}
private static void
usingJoin() {
Thread[] threads = new Thread[100];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
int
result = 0;
for
(int j = 0; j < 10000; j++) {
result += j;
}
});
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
}
}
9.7CyclicBarrier 栅栏,满后执行
package com.hy.mashibing2.knowledge;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
*
* CyclicBarrier栅栏,满了之后做后续动作
* @author hanyong
* @date 2020/9/14 23:29
*/
public class T27_CyclicBarrier {
public static void main(String[] args) {
// CyclicBarrier barrier =
new CyclicBarrier(20);
CyclicBarrier barrier = new CyclicBarrier(20,()->{
System.out.println("lamda满人发车");
});
/* CyclicBarrier
barrier = new CyclicBarrier(20, new Runnable() {
@Override
public void run() {
System.out.println("人满发车");
}
});*/
Thread[] threads = new Thread[100];
for (int i = 0; i < threads.length; i++) {
new
Thread(() -> {
try
{
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
9.8Phaser阶段锁
所有线程执行完当前阶段再开始执行下一阶段
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister();
package com.hy.mashibing2.knowledge;
import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
/**
* @author hanyong
* @date 2020/9/15 0:19
*/
public class T28_Phaser1 {
static Random r = new Random();
static Phaser phaser = new MarriagePhaser();
static void sleep(int nums) {
try {
TimeUnit.MILLISECONDS.sleep(nums);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
phaser.bulkRegister(7);
for (int i = 0; i < 5; i++) {
new Thread(new Persion("p" + i)).start();
}
new
Thread(new Persion("新郎")).start();
new
Thread(new Persion("新娘")).start();
}
static class MarriagePhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase) {
case 0:
System.out.println("所有人到齐了!" + registeredParties);
System.out.println();
return false;
case 1:
System.out.println("所有人吃完了!" + registeredParties);
System.out.println();
return false;
case 2:
System.out.println("所有人离开了!" + registeredParties);
System.out.println();
return false;
case 3:
System.out.println("婚礼结束!新娘新郎抱抱" + registeredParties);
return true;
default:
return true;
}
}
}
static class Persion implements Runnable {
String name;
public Persion(String name) {
this.name = name;
}
void arrive() {
sleep(1000);
System.out.printf("%s 到达现场! \n", name);
phaser.arriveAndAwaitAdvance();
}
void eat() {
sleep(1000);
System.out.printf("%s 吃完!\n", name);
phaser.arriveAndAwaitAdvance();
}
void leave() {
sleep(1000);
System.out.printf("%s 离开!\n", name);
phaser.arriveAndAwaitAdvance();
}
void hug() {
if (name.equals("新郎") || name.equals("新娘")) {
sleep(1000);
System.out.printf("%s 洞房!\n", name);
phaser.arriveAndAwaitAdvance();
} else {
phaser.arriveAndDeregister();
}
}
@Override
public void run() {
arrive();
eat();
leave();
hug();
}
}
}
9.9读写锁
static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
readLock为共享锁,读线程可以同时执行,writeLock为排他锁,独占执行
案例如下
package com.hy.mashibing2.knowledge;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author hanyong
* @date 2020/9/15 23:20
*/
public class T29_ReadWriterLock
{
static int value;
static ReentrantLock
lock = new ReentrantLock();
static ReentrantReadWriteLock
readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writerLock = readWriteLock.writeLock();
public static void read(Lock lock) {
try {
lock.lock();
sleep(1);
System.out.println(Thread.currentThread().getName() + "读完了");
} finally {
lock.unlock();
}
}
public static void writer(Lock lock, int v) {
try {
lock.lock();
sleep(1);
value = v;
System.out.println(Thread.currentThread().getName() + "写完了");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
//创建10个线程读
for (int i = 0; i < 10; i++) {
new Thread(() -> {
read(readLock);
}, "读线程" + i).start();
}
//创建2个线程写
for (int i = 0; i < 2; i++) {
new
Thread(() -> {
writer(writerLock,
new Random().nextInt());
}, "写线程" + i).start();
}
}
static void sleep(int time) {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException
e) {
e.printStackTrace();
}
}
}
9.10semaphore信号量
做限流
package com.hy.mashibing2.knowledge;
import java.util.concurrent.Semaphore;
/**
* @author hanyong
* @date 2020/9/16 22:09
*/
public class T30_Semaphore {
public static void main(String[] args) {
//1表示同时只能有一个线程执行
//Semaphore
semaphore=new Semaphore(1);
Semaphore semaphore=new Semaphore(1,true);//公平锁,队列,线程排队
new
Thread(()->{
try
{
semaphore.acquire();//阻塞获得,后为0
System.out.println("T1
running...");
Thread.sleep(200);
System.out.println("T1
running...");
} catch
(InterruptedException e)
{
e.printStackTrace();
}finally {
semaphore.release();//释放,后为1
}
},"t1").start();
new
Thread(()->{
try
{
semaphore.acquire();
System.out.println("T2 running");
Thread.sleep(200);
System.out.println("T2 running");
} catch
(InterruptedException e)
{
e.printStackTrace();
}finally
{
semaphore.release();
}
},"t2").start();
}
}
9.11Exchanger交换
*/
public class T31_Exchange {
static Exchanger<String> exchanger = new Exchanger();
public static void main(String[] args) {
new
Thread(() -> {
String
s = "t1";
try
{
s= exchanger.exchange(s);//双人游戏交换装备
} catch
(InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + s);
}, "线程1").start();
new
Thread(() -> {
String
s = "t2";
try
{
s= exchanger.exchange(s);
} catch
(InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + s);
}, "线程2").start();
}
}
打印结果
线程1t2
线程2t1
9.12LockSupport
package com.hy.mashibing2.knowledge;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
*
* LockSupport.park();不用加锁可以暂停线程
* LockSupport.unpark(t);可以恢复park的线程继续执行
*
LockSupport.unpark(t);可以优先于LockSupport.park();执行,这样park的时候可以不用park
*
* 内部实现类似于维护一个count,park变为0,unpark变为1,变为1线程继续执行,之前已经为1则park不停继续执行,再次变为0就停
* @author hanyong
* @date 2020/9/16 23:49
*/
public class T32_LockSupport {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for
(int i = 0; i < 10; i++) {
System.out.println(i);
if
(i == 5) {
LockSupport.park();
}
try
{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
LockSupport.unpark(t);
/*try {
TimeUnit.SECONDS.sleep(8);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("主线程睡了8秒了");
LockSupport.unpark(t);*/
}
}