1、什么是juc
java.util.concurrent
java.util.concurren.atomic(原子性)
java.util.concurrentlocks(lock锁)
2、线程和进程
进程:一个程序的集合
线程:一个进程可以包含多个线程,至少含有一个!
java默认有几个线程?2个main线程、GC回收线程
java真的可以开启线程吗?开不了
调用底层的C++,java无法操控硬件
并发和并行()
并发(多线程一个资源,cpu单核进行多个线程交替使用)
并行(cup多核多个线程)
public static void main(String[] args) {
// new Thread().start();
//获取cup的核数
System.out.println(Runtime.getRuntime().availableProcessors());
}
并发编程本质充分利电脑cup资源
线程有几个状态
//线程新生
NEW
//运行
RUNNABLE,
//阻塞
BLOCKED
//等待
WAITING
//死死的等
TIMED_WAITING
//终止
TERMINATED;
wait/sleep状态
wait=> Object
sleep=>Thread
(关于锁的释放wait会释放锁,sleep不会放锁)
使用的范围:wait必须在同步代码块中
sleep可以在任何地方使用
是否需要捕获异常:wait不需要捕获异常,sleep必须要捕获异常
lock锁(重点)
Synchronized(默认非公平锁可以插队)
public class demo02 {
public static void main(String[] args) {
//并发多个线程操作同一个资源类
Tickets02 tickets=new Tickets02();
//@functionlinterface 函数是接口 lambda表达式(参数)->{代码}
new Thread(()->{for (int i = 1; i < 60; i++)tickets.sale(); },"A").start();
new Thread(()->{for (int i = 1; i < 60; i++) tickets.sale();},"B").start();
new Thread(()->{for (int i = 1; i < 60; i++)tickets.sale();},"C").start();
;
}
}
class Tickets02{
//1属性和方法
private int number = 30;
Lock lock= new ReentrantLock(false);
//卖票的方式
//本质锁
public synchronized void sale(){
lock.lock();
try {
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+number--+"张票,剩余"+number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
Synchronized和lock的区别
1、synchronized 是java内置的关键字;lock是一个java类
2、synchronized 无法判断获取锁的状态,lock可以判断是否获取到了锁
3、synchronized 会自动释放锁,lock必须手动释放锁!如果不释放锁,死锁
4、synchronized 线程1 (获取锁,阻塞)、线程2(等待);lock锁就不一定会等待下去;
5、synchronized 可重入锁,不可以中断,非公平;lock,可重入锁可以判断锁,非公平(可以自己设置)
6、synchronized 适合少量的代码 同步问题,lock适合大量的同步锁。
锁是什么,如何判断锁的是谁?
4、生产者和消费者问题
面试的:单例模式、排序模式、生产者消费者问题、思索
生产者和消费者synchronized版 :
/*
* 线程通信问题?:生产者消费者问题|等待唤醒,通知唤醒
* 线程交替执行
* */
public class demo03 {
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();
}
}
},"B").start();
}
}
//等待 通知 业务
class data{
private int num=0;
public synchronized void increment() throws InterruptedException {
if (num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程完毕
this.notifyAll();
}
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改为while)
JUC生产者和消费者版 :
通过lock找到condition
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sHi0DAfC-1635941356140)(JUC并发编程.assets/捕获.PNG)]
public class demo04 {
public static void main(String[] args) {
Data01 data = new Data01();
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();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();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();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待 通知 业务
class Data01{
private int num=0;
Lock lock=new ReentrantLock();
Condition condition =lock.newCondition();
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();
}
}
public synchronized 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();
}
}
}
精准通知
public class demo05 {
public static void main(String[] args) {
Data03 data03=new Data03();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
data03.printA();
}
},"A").start();
new Thread(()->{for (int i = 0; i <10 ; i++) {
data03.printB();
}},"B").start();
new Thread(()->{for (int i = 0; i <10 ; i++) {
data03.printC();
}},"C").start();
}
}
class Data03{
private Lock lock=new ReentrantLock();
private Condition condition3=lock.newCondition();
private Condition condition1=lock.newCondition();
private Condition condition2=lock.newCondition();
private int num=1;
public void printA(){
lock.lock();
try {
while (num!=1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAAAAAA");
//唤醒
num=2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (num!=2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>BBBBBB");
num=3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (num!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>CCCCCC");
num=1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
5、8锁现象
public class Demo07 {
public static void main(String[] args) {
Phone phone=new Phone();
Phone phone1=new Phone();
new Thread(()->{
phone.send();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Phone{
public static synchronized void send(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
6、集合类不安全
List不安全
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qour8JTS-1635941356144)(JUC并发编程.assets/捕获-1632831200327.PNG)]
ConcurrentModificationException(并发修改异常)
public class unsafeList {
public static void main(String[] args) {
// List<String> list= Collections.synchronizedList(new ArrayList<>());
//写入时复制计算机程序优化设计领域的一种优化策略
List<String> list=new CopyOnWriteArrayList<>();//volatile
for (int i = 0; i <10 ; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
HashSet时不安全
public class unsafeSet {
public static void main(String[] args) {
// Set<String> set=new HashSet<>();
// Set<String> set= Collections.synchronizedSet(new HashSet<>());
Set<String> set=new CopyOnWriteArraySet<>();
for (int i = 1; i <=30 ; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
HashMap不完全
[加载因子和初始化容量]
public class unsafeHashMap {
public static void main(String[] args) {
// Map<String,String> map =new HashMap();
// Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
Map<String,String> map = new ConcurrentHashMap<>();
for (int i = 1; i <=30 ; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
Callable
他可以 返回值,他可以抛出异常,方法不同call()
Callable调用原理
public class test01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread thread=new MyThread();
FutureTask futureTask=new FutureTask(thread);
futureTask.run();
new Thread(futureTask,"A").start;
new Thread(futureTask,"B").start;//结果会被缓存提高效率
System.out.println(futureTask.get());//get方法会发生阻塞放到最后或者利用异//步通信
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("Call()");
return 1234;
}
}
细节问题:
1、有缓冲 2、结果可能需要等待,会阻塞。
8、常用的辅助类
8.1、CountDownLatch(减法计数器)
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"go out");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("close door");
}
}
8.2、CyclicBarrier(加法计数器)
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{
System.out.println("召唤神龙成功!");
});
for (int i = 1; i <=7 ; i++) {
final int temp=i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"召唤");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
8.3、SemaPhore(信号量)限流
例如抢车位
public class SemaPhoreDemo {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(3);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"停车了!");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开了!");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
9、读写锁
读写锁就是独占锁和共享锁
可以多个读,写入只能单个写
package com.huang.rw;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadAndWriteDemo {
public static void main(String[] args) {
CacheLock cacheLock=new CacheLock();
for (int i = 1; i <=5 ; i++) {
final int temp=i;
new Thread(()->{
cacheLock.Put(temp+"",temp+"");
},String.valueOf(temp)).start();
}
for (int i = 1; i <=5 ; i++) {
final int temp=i;
new Thread(()->{
cacheLock.Get(temp+"");
},String.valueOf(temp)).start();
}
}
}
class CacheLock{
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
private volatile Map<String,Object> map=new HashMap<>();
public void Put(String key,Object value){
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入锁");
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 {
System.out.println(Thread.currentThread().getName()+"读取中"+key);
System.out.println(Thread.currentThread().getName()+"读取成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
readWriteLock.readLock().unlock();
}
}
}
10、阻塞队列(自定义容量)
BlockingQuequ
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I1OszJPk-1635941356148)(JUC并发编程.assets/捕获-1633920444670.PNG)]
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
Test01();
}
public static void Test01() throws InterruptedException {
BlockingQueue blockingQueue=new ArrayBlockingQueue(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.offer("b"));
blockingQueue.put("c");
System.out.println(blockingQueue.offer("d", 4, TimeUnit.SECONDS));
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
}
}
11、同步队列SynchronousQueue(没有容量只能处理单个)
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue=new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"--->"+"put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName()+"--->"+"put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName()+"--->"+"put 3");
blockingQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"取出----->"+blockingQueue.take());
System.out.println(Thread.currentThread().getName()+"取出----->"+blockingQueue.take());
System.out.println(Thread.currentThread().getName()+"取出----->"+blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t2").start();
}
}
12、线程池
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WUOztLZI-1635941356150)(JUC并发编程.assets/捕获-1633923113832.PNG)]
三大方法
public class Demo01 {
public static void main(String[] args) {
// ExecutorService ThreadPool = Executors.newSingleThreadScheduledExecutor();
// ExecutorService ThreadPool=Executors.newFixedThreadPool(5);
ExecutorService ThreadPool=Executors.newCachedThreadPool();
try {
for (int i = 1; i <=10 ; i++) {
ThreadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ThreadPool.shutdown();
}
}
}
手动创建线程池以及四种拒绝方法
public static void main(String[] args) {
//ThreadPoolExecutor(1、核心线程尺寸2、最大线程尺寸3、调用额外线程后服务结束停止时间3、阻塞队列4、线程工厂创建5、拒绝线程调用方法)
ExecutorService executorService=new ThreadPoolExecutor(2,5,3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
//四种拒绝方法1、DiscardOldestPolicy 和最早执行的线程竞争,结束则执行,未结束直接强制结束最早执行线程
//2、AbortPolicy() 拒绝服务直接抛出异常
//3、CallerRunsPolicy() 回到线程执行前程序
//4、DiscardPolicy 丢掉任务不抛出异常
);
try {
for (int i = 1; i<=8 ; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
cpu密集型和io密集型(最大的线程如何去设置)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVDdcIGH-1635941356152)(JUC并发编程.assets/1.PNG)]
CPU密集型:
maxpoolsiaze定义:几核就是几
获取运行最大线程数(电脑或者服务器的核数):Runtime.getRuntime().availableProcessors()
IO密集型:
根据程序运行的最大线程数。
四大函数式接口(必须掌握)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GQsbPNfK-1635941356154)(JUC并发编程.assets/2.PNG)]
@FunctionalInterface
函数值接口:只有一个方法的接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f4RjlwWB-1635941356155)(JUC并发编程.assets/3.PNG)]
function:
public static void main(String[] args) {
// Function<String,String> function=new Function<String, String>() { //函数式接口定义
// @Override
// public String apply(String s) {
// return s;
// }
// };
Function<String,String> function=s->{ //lambda表达式
return s;
};
System.out.println(function.apply("asd"));
}
Predicate:
public class demo02 {//判断型函数接口
public static void main(String[] args) {
// Predicate<String> predicate=new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.isEmpty();
// }
// };
Predicate<String> predicate =s->{
return s.isEmpty();
};
System.out.println(predicate.test(""));
}
}
Consumer
public class demo03 {
public static void main(String[] args) {
// Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer=s -> {
System.out.println(s);
};
consumer.accept("ssssssss");
}
}
Supplier //供给型接口
public class demo04 {
public static void main(String[] args) {
// Supplier supplier=new Supplier() {
// @Override
// public Integer get() {
// return 1231231231;
// }
// };
Supplier supplier=()->{return 2132313;};
System.out.println(supplier.get().toString());
}
}
13、Stream流计算
package com.huang.Stream;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructorpublic class User { private int id; private String name; private int age;}
package com.huang.Stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
User u1=new User(1,"a",23);
User u2=new User(2,"b",24);
User u3=new User(3,"c",18);
User u4=new User(4,"d",18);
User u5=new User(5,"e",18);
User u6=new User(6,"f",25);
List<User> list =Arrays.asList(u1,u2,u3,u4,u5,u6);
list.stream().filter(u->{return u.getId()%2==0;}) .filter(u->{return u.getAge()>18;})
.map(u->{return u.getName().toUpperCase();}) .sorted((uu1,uu2)->{return uu2.compareTo(uu1);}) .limit(1)
.forEach(System.out::println); }}
14、ForkJoin(分支合并)
在jdk1.7之后出来的,并行执行任务!提高效率。大数据量。
大数据:mapReduce 将大任务变成小任务
forkjoin特点:工作窃取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0KZtr9BA-1635941356157)(JUC并发编程.assets/捕获-1635927890992.PNG)]
B线程先执行完后会帮助窃取A线程帮助执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rhq18N6P-1635941356158)(JUC并发编程.assets/捕获-1635928560255.PNG)]
测试类:
package com.huang.ForkJoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Test01();
// Test02();
Test03();
}
//普通
public static void Test01(){
long start=System.currentTimeMillis();
long sum=0L;
for (Long i = 1L; i <10_0000_0000 ; i++) {
sum +=i;
}
long end=System.currentTimeMillis();
System.out.println("sum="+sum+"时间为:"+(end-start));
}
//forkjoin
public static void Test02() throws ExecutionException, InterruptedException {
long start=System.currentTimeMillis();
ForkJoinPool forkJoinPool=new ForkJoinPool();
ForkJoinTask<Long> task=new ForkJoinDemo(0L,10_0000_0000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);//excute执行get会产生阻塞
Long sum = submit.get();
long end=System.currentTimeMillis();
System.out.println("sum="+sum+"时间为:"+(end-start));
}
//Steam并行流
public static void Test03(){
long start=System.currentTimeMillis();
//parallel是并行计算的意思
long sum = LongStream.range(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
long end=System.currentTimeMillis();
System.out.println("sum="+sum+"时间为:"+(end-start));
}
}
实现类:
package com.huang.ForkJoin;
//如何使用forkjoin
import java.util.concurrent.RecursiveTask;
/**
* 1、通过forkJoinPool通过他来执行
* 2、计算任务forkjoinpool.excute(forkjoinTask task)
*
* */
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 mid = (start + end) / 2L;
ForkJoinDemo task1= new ForkJoinDemo(start, mid);
task1.fork();//拆分任务,把任务压入线程队列
ForkJoinDemo task2 = new ForkJoinDemo(mid + 1, end);
task2.fork();
return task1.join()+task2.join();
}
}
}
e com.huang.ForkJoin;
//如何使用forkjoin
import java.util.concurrent.RecursiveTask;
/**
-
1、通过forkJoinPool通过他来执行
-
2、计算任务forkjoinpool.excute(forkjoinTask task)
* -
*/
public class ForkJoinDemo extends RecursiveTask {
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 mid = (start + end) / 2L;
ForkJoinDemo task1= new ForkJoinDemo(start, mid);
task1.fork();//拆分任务,把任务压入线程队列
ForkJoinDemo task2 = new ForkJoinDemo(mid + 1, end);
task2.fork();
return task1.join()+task2.join();
}
}
}