java----JUC详解

原创
03/11 14:05
阅读数 86

1.Thread.State

线程几种状态
New:没有启动的线程状态。
RUNNABLE:正在运行的线程。
BLOCKED:阻塞状态。
WAITING:等待状态,一直等待。
TIMED_WAITING:超时等待,时间到了就不等了。
TERMINATED:终止状态。

2.wait与sleep区别

1>来自不同的类
wait --> Object类
sleep --> Thread类
2>关于锁的释放
wait会释放锁
sleep不会释放锁
3>使用范围不同
wait:必须用在同步代码块中
sleep:可以用于任何地方
4>是否需要捕获异常
wait:不需要捕获异常
sleep:必须捕获异常

3.Lock与synchronized区别

1>synchronized的本质是队列+锁。
2>Lock是一个接口,它有如下三个实现类
ReentrantLock:可重入锁(常用)
ReadLock:读锁
WriteLock:写锁
3>区别
3.3.1 synchronized是内置java关键字;Lock是一个java类。
3.3.2 synchronized无法判断获取锁的状态;Lock可以判断是否获到了锁。
3.3.3 synchronized会自动释放锁;Lock需要手动释放锁,容易造成死锁。
3.3.4 synchronized时,如果线程1获得到锁,发生了阻塞,那么线程2会一直等待;Lock中的tryLock()方法会尝试获取锁,不会一直等待。

4.多线程间的通信问题,经典问题:生产者与消费者问题?

4.1 老版本生产者与消费者问题。
this.wait():线程等待。
this.notify():当前线程结束,通知其他所有线程。
如上这两个方法都来源Object类。
4.2 JUC版本生产者与消费者问题
//可重入锁
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//等待
condition.await();
//精准的通知与唤醒
condition.signal();
4.3读写锁,写锁又称之为独占锁,一次只能被一个线程占有;读锁称之为共享锁,多个线程同时占有。
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//写锁
readWriteLock.writeLock().lock();
//读锁
readWriteLock.readLock().lock();

5.八锁现象

synchronized锁的对象是方法的调用者,调用者有类与类的模板(class)两种。
static修饰方法在类加载的时候就生成了,即class。

6.集合类安全问题

并发下经常报的错:ConcurrentModificationException。----并发修改异常。
6.1 ArrayList线程不安全,常用如下解决方案
1>vector,即方法上加了synchronized修饰。

List<String> list = new Vector<>();  

2> Collections.synchronizedList(),即采用集合工具类对集合进行加锁。

List<String> list = Collections.synchronizedList(new ArrayList<>());

3>JUC下解决方法: 写入时复制一个对象出来,写入成功后覆盖对象。

List<String> list = new CopyOnWriteArrayList<>();

4>vector与CopyOnWriteArrayList相比:vector采用synchronized修饰,效率低;CopyOnWriteArrayList采用Lock锁机制,效率高。
6.2 HashSet线程不安全,常用如下解决方案
1>集合工具类对集合进行加锁。

Set<String> set = Collections.synchronizedSet(new HashSet<>());

2>JUC下解决方法:

Set<String> set = new CopyOnWriteArraySet<>();

3>HashSet的底层就是HashMap
6.3 HashMap线程不安全,常用如下解决方案
1>集合工具类对集合进行加锁。

Map<String,String> map = Collections.synchronizedMap(new HashMap<>());

2>JUC下解决方法:

Map<String,String> map = new ConcurrentHashMap<>();

7.JUC中常用三大辅助类

1>减法计数器CountDownLatch
CountDownLatch countDownLatch = new CountDownLatch(10);
//执行减一操作
countDownLatch.countDown();
//等待计数器归零,然后执行后续操作
countDownLatch.await();
2>加法计数器CyclicBarrier

CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
	System.out.println("达到数字10后执行打印方法!");
});

3>信号量
Semaphore semaphore = new Semaphore(10);
//得到,信号量-1,等待被唤醒
semaphore.acquire();
//释放,信号量+1,唤醒等待线程
semaphore.release();

8.队列详讲

Queue包含阻塞队列(BlockingQueue)、双端队列、非阻塞队列等。
BlockingQueue包括ArrayBlockingQueue、LinkedBlockingQueue。
BlockingQueue包含四组API
1>抛出异常
BlockingQueue.add()与BlockingQueue.remove()。
2>有返回值
BlockingQueue.offer()与BlockingQueue.poll()
3>阻塞等待,会一直阻塞
BlockingQueue.put与BlockingQueue.take()
4>超时等待
BlockingQueue.put与BlockingQueue.take()
BlockingQueue.offer(存放对象,秒值,TimeUnit.SECONDS)与BlockingQueue.poll(秒值,TimeUnit.SECONDS)

9.线程池

三大方法、7大参数、4种拒绝策略。
1>三大方法
//单例线程,线程池只有一个线程

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(()->{
	System.out.println(Thread.currentThread().getName());
});

//固定线程池的大小,线程池数是固定的

ExecutorService executorService = Executors.newFixedThreadPool(20);
executorService.execute(()->{
	System.out.println("最大new出20个线程!");
});

//cache:可伸缩的线程池大小

ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
	System.out.println(Thread.currentThread().getName());
});

三大方法的本质是ThreadPoolExecutor
2>线程池七大参数

public ThreadPoolExecutor(int corePoolSize,
						  int maximumPoolSize,
						  long keepAliveTime,
						  TimeUnit unit,
						  BlockingQueue<Runnable> workQueue,
						  ThreadFactory threadFactory,
						  RejectedExecutionHandler handler) {}

corePoolSize:核心线程数
maximumPoolSize:线程池最大数
keepAliveTime:超时时间
unit:超时时间单位
workQueue:阻塞队列
threadFactory:线程工厂
handler:拒绝策略
3>四种拒绝策略
AbortPolicy:抛出异常,默认是这个策略。
CallerRunPolicy:直接返回给主线程去处理。
DiscardPolicy:不抛出异常,程序也不处理任务,任务直接丢弃。
DiscardOldestPolicy:不会抛出异常,它会去等待下之前的任务有没有执行完成,如果之前的完成了,那么执行这个任务,否则直接丢掉任务。
9.1 最大线程数如何设置
分成CPU密集型与I/O密集型
1>CPU密集型,Runtime.getRuntime().availableProcessors()获取CPU个数,可以保证CPU效率最高。
2>I/O密集型,判断程序中消耗I/O的线程个数N,设置最大线程数为M(N<M<2N)

10.四大函数式接口

1>lambda表达式
2>链式编程
3>函数式接口
4>Stream流式计算
函数式接口:只有一个方法的接口,采用@FunctionalInterface注解修饰。例如:

@FunctionalInterface
public interface Runnable {
	public abstract void run();
}

10.1 四大原生函数式接口
1>Consumer
2>Function
3>Predicate
4>Supplier
10.1.1 Function函数型接口,有一个输入,有一个输出

Function<Integer,String> function = new Function<Integer,String>() {
	@Override
	public String apply(Integer o) {
		return String.valueOf(o);
	}
};

说明:只要是 函数式接口 都可以采用lambda表达式简化。简化如下:
Function function = (str)->{ return String.valueOf(str);};
调用:function.apply("hello world");
10.1.2 Predicate断定型接口,有一个输入,布尔值输出

Predicate<String> predicate = new Predicate<String>() {
	@Override
	public boolean test(String str) {
		return str.isEmpty();
	}
};

简化如下:

Predicate<String> predicate1 = (str)->{return str.isEmpty();}; 

10.1.3 Consumer消费型接口,只有输入,没有返回

Consumer<String> consumer = new Consumer<String>() {
	@Override
	public void accept(String str) {
		System.out.println("消费了:"+str);
	}
};

简化如下:

Consumer<String> consumer = (str)->{ System.out.println("消费了:"+str);};

10.1.4 Supplier提供型接口,没有输入,只有返回

Supplier<String> supplier = new Supplier<String>() {
	@Override
	public String get() {
		System.out.println("执行提供内容");
		return "提供成功!";
	}
};

简化如下:

Supplier<String> supplier1 = ()->{return "提供成功!";};
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部