JUC笔记
线程状态
public enum State {
// 新建
NEW,
// 运行
RUNNABLE,
// 阻塞
BLOCKED,
// 等待
WAITING,
// 超时等待
TIMED_WAITING,
// 终止
TERMINATED;
}
wait和sleep
-
来自不同的类
wait--Object
sleep--Thread
-
关于锁的释放
wait会释放锁,sleep不会释放锁
-
使用范围
wait要在同步代码块中
sleep可以在任何地方
Lock锁
synchronized
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
},"C").start();
}
}
class Ticket {
private int num = 20;
public synchronized void sale() {
if (num > 0) {
System.out.println(Thread.currentThread().getName()+"卖出"+num--);
}
}
}
Lock接口

ReentrantLock的构造函数
无参构造是非公平锁,默认的

lock的使用
-
Lock lock = new ReentrantLock(); -
public void sale() { // 加锁 lock.lock(); try{ if (num > 0) { System.out.println(Thread.currentThread().getName()+"卖出"+num--); } } catch (Exception e) { e.printStackTrace(); } finally { // 解锁 lock.unlock(); } }
synchronized和lock的区别
- synchronized是java的关键字,Lock是一个java接口
- synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
- synchronized会自动释放锁,Lock必须手动释放
- synchronized适合锁少量的代码同步问题,Lock都可以使用
生产者和消费者问题
synchronized
public class TestPC {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"N").start();
}
}
class Data {
private int num = 0;
// +1
public synchronized void increment() throws InterruptedException {
if (num !=0 ) {
// 等待
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=="+num);
// 通知其他线程
this.notifyAll();
}
// -1
public synchronized void decrement() throws InterruptedException {
if(num == 0) {
// 等待
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=="+num);
this.notifyAll();
}
}
如果有A、B、C、D四个线程会存在问题

在减一之后会唤醒线程,有两个生产者,所以这两个生产者都被唤醒后不会重新判断if条件,直接执行if后面的+1,用while的话会重新判断是否需要等待
if改为while
JUC的生产者和消费者问题


public class B {
public static void main(String[] args) {
Data2 data2 = new Data2();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data2.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data2.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data2.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data2.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Data2 {
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// +1
public void increment() throws InterruptedException {
lock.lock();
try {
while (num !=0 ) {
// 等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName()+"=="+num);
// 通知其他线程
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// -1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (num == 0) {
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+"=="+num);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition精准的通知和唤醒线程
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
// A执行完--B--C,顺序执行
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 Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int flag = 1;
public void printA() {
lock.lock();
try {
// 判断--执行--通知
while (flag != 1) {
// 等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"====AAAA");
// 唤醒指定的B
flag = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (flag != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"====B");
flag = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (flag != 3) {
condition3.await();
}
System.out.println("C");
flag = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
8锁现象
找出锁的是什么
- synchronized两个线程用的是同一个锁,先发短信后打电话
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone {
// synchronized锁的是Phone的同一个对象
public synchronized void sendMessage() throws InterruptedException {
Thread.sleep(2000);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
- 先输出hello,等待2秒发短信,因为hello没有同步锁
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone.hello();
},"B").start();
}
}
class Phone {
public synchronized void sendMessage() throws InterruptedException {
Thread.sleep(2000);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
- 输出打电话,发短信
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
//TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone {
public synchronized void sendMessage() throws InterruptedException {
Thread.sleep(2000);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
- static方法
发短信,打电话
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Phone2 phone = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
//TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone2.call();
},"B").start();
}
}
// Phone2唯一的class
class Phone2 {
// synchronized锁的是Phone2.class
public static synchronized void sendMessage() throws InterruptedException {
Thread.sleep(2000);
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
- 一个static同步方法,一个普通的同步方法
先打电话,然后发短信,因为static同步方法锁的是Phone的class,普通的同步方法锁的是调用对象
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Phone2 phone = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
//TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone.call();
},"B").start();
}
}
// Phone2唯一的class
class Phone2 {
// synchronized锁的是Phone2.class
public static synchronized void sendMessage() throws InterruptedException {
Thread.sleep(2000);
System.out.println("发短信");
}
// 普通的同步方法
public synchronized void call() {
System.out.println("打电话");
}
}
集合类不安全
list不安全
public class ListTest {
public static void main(String[] args) {
// java.util.ConcurrentModificationException 并发修改异常
// 解决方法
// 1. List<String> list = new Vector<>();
// 2. List<String> list = Collections.synchronizedList(new ArrayList<>());
// 3. List<String> list = new CopyOnWriteArrayList<>();
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <=20; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
set不安全
public class SetTest {
public static void main(String[] args) {
// Set<String> set = new HashSet<>(); 并发修改异常
/*
解决方法:
Set<String> set = Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet();
*/
Set<String> set = new CopyOnWriteArraySet();
for (int i = 1; i <= 20; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
hashset的底层就是hashmap
public HashSet() {
map = new HashMap<>();
}
HashMap

public class MapTest {
public static void main(String[] args) {
// 默认容量16,加载因子0.75
// java.util.ConcurrentModificationException
// Map<Object, Object> map = new HashMap<>();
// 解决方法
Map<Object, Object> map = new ConcurrentHashMap<>();
for (int i = 1; i < 20; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
callable


public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new Runnable() {}).start();
// FutureTask实现了Runnable接口
// new Thread(new FutureTask<V>() {}).start();
// FutureTask有个带callable参数的构造函数
// new Thread(new FutureTask<V>(Callable) {}).start();
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask(myThread);
// 输出A
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start();
Object o = futureTask.get(); // get方法可能会阻塞,放到最后
System.out.println(o);
}
}
class MyThread implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
System.out.println(Thread.currentThread().getName());
return true;
}
}
- fuctureTask只能使用一次,此时不是new状态,会直接结束线程
- get方法可能会阻塞
常用的辅助类
CountDownLatch
减法计数器
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
// 总数是6
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"出去了");
countDownLatch.countDown();// -1
},String.valueOf(i)).start();
}
// 等待执行完,计数器归0,再往下执行
countDownLatch.await();
System.out.println("执行完毕");
}
}
CyclicBarrier
加法计数器
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{
System.out.println("集齐了");
});
for (int i = 1; i <= 6; i++) {
final int temp = i;
new Thread(()->{
System.out.println("得到"+temp);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
Semaphore
计数信号量,多个共享资源互斥使用
semaphore.acquire() 获取信号量,如果没有剩余则等待
semaphore.release() 释放信号量
public class SemaphoreTest {
public static void main(String[] args) {
// 可用数量为3
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i < 6; i++) {
new Thread(()->{
// acquire() 得到
// release() 释放
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"拿到");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"离开了");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
读写锁
ReentrantReadWriteLock
独占锁-写锁 共享锁-读锁
读-读 可以共存 读和写,写和写不能共存
public class ReadWriteLockTest {
public static void main(String[] args) {
MyCacheLock myCache = new MyCacheLock();
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
myCache.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
// 加入读写锁
class MyCacheLock {
private volatile Map<String ,Object> map = new HashMap<>();
// 读写锁
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 写,写入的时候,同时只有一个线程
public void put(String key, Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
// 读
public void get(String key) {
// 读锁,防止写的时候进行读,脏读
readWriteLock.readLock().lock();
try {
Object o = map.get(key);
System.out.println("读取"+o);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
/*
自定义缓存
*/
// 读写混乱
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()+"写入完毕");
}
// 读
public void get(String key) {
Object o = map.get(key);
System.out.println("读取"+o);
}
}
阻塞队列

写入时,如果队列满了,必须阻塞等待
读取时,如果队列空的,必须阻塞等待

抛出异常
/*
抛出异常
*/
public static void test1() {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("A"));
System.out.println(blockingQueue.add("B"));
System.out.println(blockingQueue.add("C"));
// 再添加会抛出异常java.lang.IllegalStateException: Queue full
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
// 再移除会抛出异常java.util.NoSuchElementException
}
有返回值
public static void test2() {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("A"));
System.out.println(blockingQueue.offer("B"));
System.out.println(blockingQueue.offer("C"));
// 不抛出异常,输出false
System.out.println(blockingQueue.offer("A"));
System.out.println(blockingQueue.peek());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
// 不抛出异常,返回null
System.out.println(blockingQueue.poll());
}
阻塞等待
/*
等待,一直阻塞
*/
public static void test3() throws InterruptedException {
ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.put("A");
blockingQueue.put("B");
blockingQueue.put("C");
// 会一直等
//blockingQueue.put("D");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
// 会一直阻塞
//System.out.println(blockingQueue.take());
}
等待,超时退出
public static void test4() throws InterruptedException {
ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("A");
blockingQueue.offer("b");
blockingQueue.offer("c");
blockingQueue.offer("d",3, TimeUnit.SECONDS);
System.out.println("============");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
blockingQueue.poll(2,TimeUnit.SECONDS);
}
SynchronousQueue
进去一个元素,必须等待取出来才能再放入
public class SynchronousQueueTest {
public static void main(String[] args) {
SynchronousQueue<String> queue = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"=="+"1");
queue.put("A");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"=="+"2");
queue.put("B");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"=="+"3");
queue.put("C");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+queue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+queue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t2").start();
}
}
线程池(重点)
程序运行会占用系统资源,创建和销毁十分浪费资源,优化资源的使用---池化技术
池化技术:事先准备好一些资源,有人要,从我这里拿
线程池的好处:
- 降低资源的消耗
- 提高响应的速度
- 方便管理
线程池三大方法
public static void main(String[] args) {
//ExecutorService pool = Executors.newSingleThreadExecutor();// 单个线程池
//ExecutorService pool = Executors.newFixedThreadPool(3);// 创建固定大小的线程池
ExecutorService pool = Executors.newCachedThreadPool(); // 可变的线程池,最大与cpu有关
try {
for (int i = 0; i < 10; i++) {
pool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池使用完要关闭
pool.shutdown();
}
}
7大参数
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
本质都是ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, // 核心线程池大小
int maximumPoolSize, // 最大线程池大小
long keepAliveTime,// 超时时间
TimeUnit unit, // 超时单位
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler // 拒绝策略) {
阿里巴巴开发规范,建议使用ThreadPoolExecutor创建

// 自定义线程池
ExecutorService pool = new ThreadPoolExecutor(2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());
try {
// 最大承载=maximunPoolsize5+队列的大小3
for (int i = 1; i <= 10; i++) {
pool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池使用完要关闭
pool.shutdown();
}
拒绝策略

new ThreadPoolExecutor.AbortPolicy() 满了还有线程要执行,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() 哪里来的去哪里调用
new ThreadPoolExecutor.DiscardPolicy() 满了会丢掉任务,不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy() 满了会和最早的竞争,成功执行失败丢掉,不会抛出异常
cpu密集型和IO密集型
线程池大小设置
1.cpu密集型 根据cpu的核来,几核为几个 Runtime.getRuntime().availableProcessors()
2. IO密集型 判断程序中十分耗IO的线程
四大函数式接口
函数式接口:只有一个方法的接口
Function

/*
Function函数型接口,给什么输出什么
可以用lamda简化
*/
public static void main(String[] args) {
Function function = new Function<String,Object>() {
@Override
public Object apply(String str) {
return str;
}
};
Function function2 = (str)->{return str;};
System.out.println(function2.apply("aaa"));
}
Predicate
返回boolean
/*
断定型接口
一个参数,返回Bool
*/
public static void main(String[] args) {
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};
Predicate<String> predicate2 = (str)->{return str.isEmpty();};
System.out.println(predicate2.test(""));
}
Consumer
只有输入没有返回值
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer2 = (s) ->{
System.out.println(s);
};
Supplier
没有输入,有返回
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "A";
}
};
System.out.println(supplier.get());
Supplier supplier2 = ()->{return "B";};
System.out.println(supplier2.get());
Stream流式计算
/*
id大于2
年龄大于20
用户名转为大写字母
用户名字母倒序
只输出一个用户
*/
public static void main(String[] args) {
User u1 = new User(1, "a", 12);
User u2 = new User(2, "b", 16);
User u3 = new User(3, "c", 22);
User u4 = new User(4, "d", 26);
User u5 = new User(5, "e", 33);
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
// 计算交给stream流
list.stream()
.filter((user)->{return user.getId() > 2;})
.filter(user -> {return user.getAge() > 20;})
.map(user -> {return user.getName().toUpperCase();})
.sorted((n1,n2)->{return n2.compareTo(n1);})
.limit(1)
.forEach(System.out::println);
}
ForkJoin
并行执行任务,提高效率,大数据量
ForkJoin特点:工作窃取


forkjoin测试类
public class ForkJoin extends RecursiveTask<Long> {
/*
forkjoinpool来执行
计算任务forkjoin.execute(Forkjointask)
*/
private long start;
private long end;
// 临界值
private long temp = 10000L;
public ForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
public void getSum() {
if((end-start) > temp) {
// 如果计算的量很大,使用forkjoin分支合并计算
} else {
Long sum = 0L;
for (Long i = start; i < end ; i++) {
sum += i;
}
System.out.println(sum);
}
}
@Override
protected Long compute() {
if((end-start) < temp) {
Long sum = 0L;
for (Long i = start; i < end ; i++) {
sum += i;
}
return sum;
} else {
// 如果计算的量很大,使用forkjoin分支合并计算
Long middle = (start + end)/2;
ForkJoin task1 = new ForkJoin(start, middle);
task1.fork(); // 拆分任务,把任务压入线程队列
ForkJoin task2 = new ForkJoin(middle + 1, end);
task2.fork();
return task1.join()+task2.join();
}
}
}
使用forkjion和并行流
// 使用forkjoin
public static void test2() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoin(1L,100000000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);
Long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("sum="+sum+"----时间"+(end-start));
}
public static void test3() {
long start = System.currentTimeMillis();
// stream并行流
long sum;
sum = LongStream.rangeClosed(0L, 100000000L).parallel().reduce(0, Long::sum);
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + "----时间" + (end - start));
}
异步回调
/*
异步调用:CompletableFucture
异步执行
成功回调
失败回调
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 发起一个请求
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
});
System.out.println("aaa");
completableFuture.get();
// 有返回值的supplyAsync异步回调
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
//int a = 12/0;
return 12;
});
Integer result = completableFuture1.whenComplete((t, u) -> {
System.out.println("t==" + t); // 正常的返回结果
System.out.println("u==" + u); // 错误的信息
}).exceptionally((e) -> {
System.out.println(e.getMessage());
return 404; // 可以获取到错误的返回结果
}).get();
System.out.println(result);
JMM(java内存模型)
JMM:java内存模型,是概念,约定
关于JMM同步的约定:
- 线程解锁前,必须把共享变量立刻更新到主存
- 线程加锁前,必须读取主存中变量最新值到工作内存中
- 加锁和解锁是同一把锁
8种操作
read读取 load载入 use使用 assign赋值 write写入 store存储 lock加锁 unlock解锁

问题
主线程虽然修改了,主存中a为1,但是第一个线程a还是0,程序不会停
private static int a = 0;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while (a == 0) {
}
}).start();
TimeUnit.SECONDS.sleep(1);
a = 1; // main线程修改
System.out.println(a);
}
解决使用Volatile
Volatile
Volatile是java虚拟机提供轻量级的同步机制
- 保证可见性
- 不保证原子性
- 禁止指令重排
保证可见性
// 加volatile可以保证可见性,主线程main修改了a 第一个线程会知道
private volatile static int a = 0;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while (a == 0) {
}
}).start();
TimeUnit.SECONDS.sleep(1);
a = 1; // main线程修改
System.out.println(a);
}
不保证原子性
//violate不保证原子性
private volatile static int num = 0;
public static void add() {
num++;
}
public static void main(String[] args) {
for (int i = 1; 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(num);
}
解决:把add方法加synchronized,或者使用lock锁
使用原子类也可以解决

private volatile static AtomicInteger num = new AtomicInteger(0);
public static void add() {
num.getAndIncrement();
}
public static void main(String[] args) {
for (int i = 1; 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(num);
}
指令重排
写的程序,计算机并不是按照写的那样去执行的
源代码-->编译器优化的重排/指令并行也可能会重排/内存系统重排-->执行
处理器在进行指令重排的适合,会考虑数据之间的依赖性
int a = 1; // 1
int b = 2; // 2
a = a + 5; // 3
b = a * a; // 4
期望的顺序是1234
执行的顺序可能是2134 1324,对程序的运行结果没有影响
问题:
设xyab默认为0
| 线程A | 线程B |
|---|---|
| x=a | y=b |
| b=1 | a=2 |
指令重排的话
| 线程A | 线程B |
|---|---|
| b=1 | a=2 |
| x=a | y=b |
这样xy的数值会有问题
violate可以避免指令重排
内存屏障

单例模式
饿汉式
// 饿汉式单例
public class Hungry {
private Hungry() {
}
// 会浪费空间
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
懒汉式
// 懒汉式单例
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName());
}
private volatile static LazyMan lazyMan;
// 双重检查锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance() {
if(lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null)
lazyMan = new LazyMan(); // 不是一个原子性操作
/*
分配内存空间
执行构造方法,初始化对象
把这个对象指向这个空间
*/
// 使用volatile防止指令重排
}
}
return lazyMan;
}
public static void main(String[] args) {
for (int i = 0; i < 10 ; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
静态内部类
public class Holder {
private Holder() {
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
单例不安全可以通过反射破坏
第一种,使用反射获取构造器
// 懒汉式单例
public class LazyMan {
private LazyMan() {
System.out.println(Thread.currentThread().getName());
}
private static LazyMan lazyMan;
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
LazyMan instance = LazyMan.getInstance();
LazyMan instance2 = LazyMan.getInstance();
System.out.println(instance == instance2); // 正常,true
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
// 设置在使用构造器的时候不执行权限检查,破坏程序的封装性和安全性
declaredConstructor.setAccessible(true);
LazyMan instance3 = declaredConstructor.newInstance();
LazyMan instance4 = declaredConstructor.newInstance();
//问题1:
System.out.println(instance == instance3); // false
}
}
问题1解决,修改构造函数,加同步锁
private LazyMan() {
synchronized (LazyMan.class) {
if (lazyMan != null) {
throw new RuntimeException("error");
}
}
}
问题2
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
// 设置在使用构造器的时候不执行权限检查,破坏程序的封装性和安全性
declaredConstructor.setAccessible(true);
LazyMan instance3 = declaredConstructor.newInstance();
LazyMan instance4 = declaredConstructor.newInstance();
System.out.println(instance3 == instance4); // false
问题2,解决
private static boolean henry = false;
private LazyMan() {
synchronized (LazyMan.class) {
if (!henry) {
henry = true;
} else {
throw new RuntimeException("error");
}
}
}
问题是,如果知道henry变量的名字,还是可以破坏单例
Field field = LazyMan.class.getDeclaredField("henry");
field.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
// 设置在使用构造器的时候不执行权限检查,破坏程序的封装性和安全性
declaredConstructor.setAccessible(true);
LazyMan instance3 = declaredConstructor.newInstance();
// 修改henry变量值
field.set(instance3,false);
LazyMan instance4 = declaredConstructor.newInstance();
System.out.println(instance3 == instance4); // false
枚举类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
// java.lang.NoSuchMethodException: com.single.EnumSingle.<init>()
System.out.println(instance1 == instance2);
}
}

反编译EnumSingle.class,发现也有个无参构造

使用Jad程序EnumSinle.class变为java文件,实际上是有个两个参数的构造

修改
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1 == instance2);
报错,提示不能破坏枚举单例

深入理解CAS
// CAS 比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(20);
// 期望,更新
// public final boolean compareAndSet(int expect, int update)
// 如果期望的值达到了则更新
atomicInteger.compareAndSet(20, 21);
System.out.println(atomicInteger.get());
// 期望20实际上是21,不更新
System.out.println(atomicInteger.compareAndSet(20, 22));
}
cas底层使用unsafe类


cas:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,则执行操作,如果不是就一直循环(自旋锁)
缺点:循环会耗时,一次只能保证一个共享变量的原子性,ABA问题
ABA问题

AtomicInteger atomicInteger = new AtomicInteger(20);
// 捣乱的线程
atomicInteger.compareAndSet(20, 21);
atomicInteger.compareAndSet(21, 20);
// 正常的线程
atomicInteger.compareAndSet(20,22);
// 虽然这个时候期望值的还是20,但是被动过了
System.out.println(atomicInteger.get());
原子引用
AtomicStampedReference和乐观锁原理类似,使用版本号
public static void main(String[] args) {
AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(20, 1);
new Thread(()->{
// 获得版本号
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"=="+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(stampedReference.compareAndSet(20, 21, stampedReference.getStamp(), stampedReference.getStamp() + 1));
System.out.println("a2="+stampedReference.getStamp());
System.out.println(stampedReference.compareAndSet(21, 20, stampedReference.getStamp(), stampedReference.getStamp() + 1));
},"a").start();
new Thread(()->{
// 和乐观锁原理类似
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"=="+stamp);
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(stampedReference.compareAndSet(20,22,stamp,stamp+1));;
System.out.println("b2="+stampedReference.getStamp());
},"a").start();
}
各种锁
公平锁、非公平锁
公平锁:非常公平,不能插队
非公平锁:不公平,可以插队
ReentrantLock lock = new ReentrantLock();
// 实现
public ReentrantLock() {
sync = new NonfairSync();
}
// 默认是非公平锁
// 设置参数true
ReentrantLock lock = new ReentrantLock(true);
可重入锁
可以重复获取相同的锁,synchronized和ReentranLock都是可重入的
synchronized
public class LockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
// 线程a和b都是用的phone这个对象锁
new Thread(()->{
phone.sms();
},"a").start();
new Thread(()->{
phone.sms();
},"b").start();
}
}
class Phone{
public synchronized void sms() {
System.out.println(Thread.currentThread().getName()+"发短信");
call();
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName()+"打电话");
}
}
lock,是两把锁
class Phone{
Lock lock = new ReentrantLock();
public void sms() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"发短信");
call();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void call() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"打电话");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
自旋锁
public class SpinLockDemo {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
// 加锁
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"==mylock");
// 自旋锁
while (!atomicReference.compareAndSet(null,thread)) {
}
}
// 解锁
public void myUnlock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"==mylock");
atomicReference.compareAndSet(thread,null);
}
}
死锁
互相想要对方的资源
public class Slock {
public static void main(String[] args) {
String source1 = "s1";
String source2 = "s2";
new Thread(new MyThread(source1,source2),"t1").start();
new Thread(new MyThread(source2,source1),"t2").start();
}
}
class MyThread implements Runnable{
String source1 = "s1";
String source2 = "s2";
public MyThread(String source1, String source2) {
this.source1 = source1;
this.source2 = source2;
}
@Override
public void run() {
synchronized (source1) {
System.out.println(Thread.currentThread().getName()+"得到了"+source1+"等待"+source2);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (source2) {
System.out.println(Thread.currentThread().getName()+"得到了"+source2+"等待"+source1);
}
}
}
}
// t1得到了s1等待s2
// t2得到了s2等待s1
解决死锁问题
1.使用jps -l 定位到死锁的进程

2.使用jstack 进程号 找到死锁问题


浙公网安备 33010602011771号