一、基础回顾
实现线程的三种方式,1.继承thread 2.实现runnable 3.实现callable接口
进程与线程:线程是进程的最小单位
java默认有几个线程:main,gc
java可以开启线程吗?java开启不了,是调用三方库
并发与并行:
线程有几个状态:Thread.state
wait/sleep的区别:
1.来自不同的类 wait -->object sleep–>thread
2.关于锁的释放: wait释放锁 sleep不释放锁
3.使用范围不同: wait 必须在同步代码块中使用,sleep没有限制
真正的多线程开发,公司里面的开发,线程是一个单独的资源类,没有任务附属的操作(OOP)
二、Synchronized
本质:队列,锁
1. synchronized和locked的区别
2.生产者消费者模式 新版和老版本
/**
* 生产者消费者 老版
* 三步:判断等待,业务,唤醒
*/
public class OldProductAndCustomerTest {
public static void main(String[] args) {
A a = new A();
new Thread(()->{
for (int i = 0; i < 10; i++) {
a.product();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
a.customer();
}
},"b").start();
}
}
class A{
private int number=0;
public synchronized void product(){
try {
while(number !=0){
this.wait();
}
number=number+1;
System.out.println(Thread.currentThread().getName()+" number -->"+number);
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
public synchronized void customer(){
try {
while (number==0){
this.wait();
}
number = number-1;
System.out.println(Thread.currentThread().getName()+" number -->"+number);
this.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 生产者消费者 新版
* 三步:判断等待,业务,唤醒
*/
public class NewProductAndCustomerTest {
public static void main(String[] args) {
B b = new B();
new Thread(()->{
for (int i = 0; i < 10; i++) {
b.product();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
b.customer();
}
},"b").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
b.product();
}
},"c").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
b.customer();
}
},"d").start();
}
}
class B{
private int number=0;
private Lock lock= new ReentrantLock();
private Condition condition = lock.newCondition();
public void product(){
lock.lock();
try {
while(number !=0){
condition.await();
}
number=number+1;
System.out.println(Thread.currentThread().getName()+" number -->"+number);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
return;
}
public void customer(){
lock.lock();
try {
while (number==0){
condition.await();
}
number = number-1;
System.out.println(Thread.currentThread().getName()+" number -->"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
3.虚假唤醒
三、Condition实现精准通知唤醒
/**
* 生产者消费者 精准唤醒
* 三步:判断等待,业务,唤醒
*/
public class ConditionProductAndCustomerTest {
public static void main(String[] args) {
C c = new C();
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.printA();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.printB();
}
},"b").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.printC();
}
},"c").start();
}
}
class C{
private int number=1;//1A 2B 3C
private Lock lock= new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void printA(){
lock.lock();
try {
while(number !=1){
condition1.await();
}
number=2;
System.out.println(Thread.currentThread().getName()+" number -->AAAAA");
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
return;
}
public void printB(){
lock.lock();
try {
while (number!=2){
condition2.await();
}
number = 3;
System.out.println(Thread.currentThread().getName()+" number -->BBBBBB");
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number!=3){
condition3.await();
}
number = 1;
System.out.println(Thread.currentThread().getName()+" number -->CCCCC");
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
四、八锁现象
锁类,锁对象
五、集合类的不安全解决方案
六、callable
七、三大辅助类
1.countDownLatch
2.cyclicBarrier
3. semaphore
八、读写锁 ReadWriteLock
九、阻塞队列
阻塞队列应用场景:多线程并发处理,线程池!
1.队列的整个家族
2.BlockingQueue
3.队列的四组API
4.同步队列
十、线程池
1.三大方法
2.七大参数
3.四大拒绝策略
4.CPU密集型和IO密集型
解决池的最大的大小
十一、forkjoin
ForkJoin是由JDK1.7后提供多线并发处理框架。主要用于并行计算中,和 MapReduce 原理类似,都是把大的计算任务拆分成多个小任务并行计算。
forkjoin的特点工作窃取,每个维护的是双端队列
/**
* 求和计算任务
* 如何使用forkjoin?
* 1.forkjoinPool通过它来执行
* 2.计算任务forkjoinPool.execute(ForkJoinTask task)
* 3.计算类要继承ForkJoinTask
*/
public class ForkJoinDemo extends RecursiveTask<Long> {
private Long start ;
private Long end;
private Long temp =10000L;
public ForkJoinDemo(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if((end-start)<temp){
Long sum=0L;
for (Long i = start; i < end; i++) {
sum += i;
}
return sum;
}else {
long middle =(end+start)/2;
ForkJoinDemo task1 = new ForkJoinDemo(start,middle);
ForkJoinDemo task2 = new ForkJoinDemo(middle+1,end);
task1.fork();//拆分任务,把任务压入线程队列
task2.fork();
return task1.join()+task2.join();
}
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class ForkJoinTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// test1();
test2();
// test3();
}
public static void test1(){
long sum =0;
long start = System.currentTimeMillis();
for (long i = 0l; i < 10_0000_0000; i++) {
sum+=i;
}
long end = System.currentTimeMillis();
System.out.println("sum="+sum+"耗时:"+(end-start));
}
public static void test2() throws ExecutionException, InterruptedException {
long sum =0;
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinDemo(0l,10_0000_0000l);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);
sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("sum="+sum+"耗时:"+(end-start));
}
public static void test3(){
long sum =0;
long start = System.currentTimeMillis();
sum = LongStream.rangeClosed(0l,10_0000_0000l).parallel().reduce(0,Long::sum);
long end = System.currentTimeMillis();
System.out.println("sum="+sum+"耗时:"+(end-start));
}
}