JUC第七课——复习、线程池

面试题

要求用线程顺序打印A1B2C3…Z26

LockSupport

package character07;

import java.util.concurrent.locks.LockSupport;

/**
 * @author laimouren
 */
public class T08_00_LockSupport {

    static Thread t1 = null,t2=null;

    public static void main(String[] args) throws  Exception{

        char[] char1_7 = "1234567".toCharArray();

        char[] charA_G = "ABCDEFG".toCharArray();

        t1 = new Thread(()->{
            for (char c :char1_7){
                System.out.println(c);
                LockSupport.unpark(t2); //叫醒T2
                LockSupport.park();//T1线程阻塞
            }
        },"t1");

        t2 = new Thread(()->{
            for (char c :charA_G){
                LockSupport.park();//T2线程阻塞
                System.out.println(c);
                LockSupport.unpark(t1); //叫醒T1
            }
        },"t2");

        t1.start();
        t2.start();
    }

}

sync + wait + notify

package character07;

/**
 * @Author laimouren
 * @Date 2022/1/5 9:15
 */
public class Sync_wait_notify {
    public static void main(String[] args) {
        final Object o = new Object();

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        new Thread(()->{
            synchronized (o) {
                for(char c : aI) {
                    System.out.print(c);
                    try {
                        o.notify(); //叫醒其他线程 不会出让锁
                        o.wait(); // 线程阻塞 让出锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify(); //必须,否则无法停止程序
            }

        }, "t1").start();

        new Thread(()->{
            synchronized (o) {
                for(char c : aC) {
                    System.out.print(c);
                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify();
            }
        }, "t2").start();
    }
}

Condition

package character07;


/*
 * Condition本质是锁资源上不同的等待队列
 * @Auther  laimouren
 */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T09_00_lock_condition {

    public static void main(String[] args) {

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        Lock lock = new ReentrantLock();
        Condition conditionT1 = lock.newCondition();
        Condition conditionT2 = lock.newCondition();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aI) {
                    System.out.println(c);
                    conditionT2.signal();//叫醒另一个
                    conditionT1.await();//当前的等待
                }

                conditionT2.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t1").start();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aC) {
                    System.out.println(c);
                    conditionT1.signal();
                    conditionT2.await();
                }

                conditionT1.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t2").start();
    }
}

CAS

package character07;

/*
 * @Auther  laimouren
 */

public class T03_00_cas {

    enum ReadyToRun {T1, T2}

    static volatile ReadyToRun r = ReadyToRun.T1; //思考为什么必须volatile:保证线程可见性

    public static void main(String[] args) {

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        new Thread(() -> {

            for (char c : aI) {
                while (r != ReadyToRun.T1) {}
                System.out.println(c);
                r = ReadyToRun.T2;
            }

        }, "t1").start();

        new Thread(() -> {

            for (char c : aC) {
                while (r != ReadyToRun.T2) {}
                System.out.println(c);
                r = ReadyToRun.T1;
            }
        }, "t2").start();
    }
}

BlockingQueue(纯炫技)

package character07;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @Author laimouren
 * @Date 2022/1/5 9:38
 */
public class T10_00_BlockingQueue {
    static BlockingQueue<String> q1 = new ArrayBlockingQueue<>(1);
    static BlockingQueue<String> q2 = new ArrayBlockingQueue<>(1);

    public static void main(String[] args) {
        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();
        new Thread(()->{
            for (char c: aI) {
                System.out.println(c);
                try{
                    //线程1先往q1添加值
                    q1.put("ok");
                    //线程1往q2里拿值,q2没有值则会在这阻塞住
                    q2.take();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        },"t1").start();
        new Thread(()->{
            for (char c: aC) {
                try{
                    //线程2判断线程1是否往q1添加了ok,没有则线程会在这阻塞住
                    q1.take();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(c);
                try {
                    //线程2往q2里放值,以确保线程1继续执行
                    q2.put("ok");
                }catch (InterruptedException e){
                    e.printStackTrace();;
                }
            }
        },"t2").start();
    }
}

线程池常用类

Executor

执行器,这是一个接口,内部维护了一个方法execute它负责执行一项任务。参数为Runnable,方法的具体实现由我们自己来执行。
定义与运行分开

/**
The Executor implementations provided in this package implement ExecutorService, which is a more extensive interface. The ThreadPoolExecutor class provides an extensible thread pool implementation. The Executors class provides convenient factory methods for these Executors.
Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.
**/
public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

如下面的代码,我们既可以使用单纯的方法调用也可以新启一个新的线程去执行Runnable的run方法。

package character07.ThreadPool;

import java.util.concurrent.Executor;
 
public class T01_MyExecutor implements Executor {
 
	public static void main(String[] args) {
		new T01_MyExecutor().execute(()->System.out.println("hello executor"));
	}
 
	@Override
	public void execute(Runnable command) {
		//new Thread(command).run();
		command.run();
	}
 
}

ExecutorService

代表着启动一系列的线程为用户提供服务(本质上也是一个执行器),比如说Java8的官方文档就举了一个网络接受连接池的例子(代码如下)。在这里ExecutorService就代表着一个的线程池对外提供接受网络请求的服务。同时它也是一系列线程池的接口比如说

RorkJoinPool、ScheduledThreadPoolExecutor,、ThreadPoolExecutor等。同时它可以提交Callable与Runnable的对象返回一个未来的执行结果对象Future。

class NetworkService implements Runnable {
   private final ServerSocket serverSocket;
   private final ExecutorService pool;
 
   public NetworkService(int port, int poolSize)
       throws IOException {
     serverSocket = new ServerSocket(port);
     pool = Executors.newFixedThreadPool(poolSize);
   }
 
   public void run() { // run the service
     try {
       for (;;) {
         pool.execute(new Handler(serverSocket.accept()));
       }
     } catch (IOException ex) {
       pool.shutdown();
     }
   }
 }
 
 class Handler implements Runnable {
   private final Socket socket;
   Handler(Socket socket) { this.socket = socket; }
   public void run() {
     // read and service request on socket
   }
 }

除了以上方法来创建一个ExecutorService还可以使用Executors这个工具类来创建它,在这里我们可以把Executors理解为就像utils,collections的工具类。

Callable

Callable是一个增强版的Runnable,它的call方法可以抛出异常可以有返回值。其中它的返回值放在了Future对象中,我们可以使用Future对象的get方法来获得返回值。

package character07.ThreadPool;

import java.util.concurrent.*;

/**
 * @Author laimouren
 * @Date 2022/1/5 10:25
 */
public class T03_Callable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> c = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "Hello callable";
            }
        };

        ExecutorService service = Executors.newCachedThreadPool();
        Future<String> future = service.submit(c);//异步执行
        //get方法是阻塞的
        System.out.println(future.get());
        service.shutdown();
    }
}

Future

== 将来的结果==
Future常与Callable联合使用,Future可以获得Callable执行后的返回值。如果想新建一个线程执行一个这个Callable中的call方法而且获得返回值的话我们可以使用以下的思路。

方案一:new Thread(new FutureTask().start();使用FutureTask来接收任务的返回值。

方案二:new一个线程池然后然后提交Callable的实现的对象。使用Future来获得Callable的返回值。

FutureTask

实现了RunnableFuture接口,而RunnableFuture又实现了Runable接口和Future接口,所以即可以运行,也可以储存返回值

package character07.ThreadPool;
 
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
 
public class T06_Future {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		FutureTask<Integer> task = new FutureTask<>(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1000;
		}); //new Callable () { Integer call();}
		
		new Thread(task).start();
		
		System.out.println(task.get()); //阻塞
		
		//*******************************
		ExecutorService service = Executors.newFixedThreadPool(5);
		Future<Integer> f = service.submit(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1;
		});
		System.out.println(f.get());
		System.out.println(f.isDone());
		
	}
}

Callable、Future和FutureTask

Callable->Runnable + ret
Future -> 存储执行的将来才会产生的结果
FutureTask->Future + Runnable

CompletableFuture

看资料

线程池

  1. ThreadPoolExecutor
  2. ForkJoinPool

ThreadPoolExecutor

继承自AbstractExecutorService,而AbstractExecutorService又实现了ExecutorService接口
深入理解ThreadPoolExecutor

线程池定义

维护着两个集合,一个是线程集合,一个是任务集合

线程池7个参数

第一个参数corePoolSize 核心线程数
第二个参数maxmumPoolSize 最大线程数
第三个参数keepAliveTime 空闲时间 如果到了指定空闲时间线程都没有干活 将归还给操作系统
第四个参数是第三个参数的单位
第五个参数 BlockingQueue 阻塞队列
第六个参数 默认的线程工厂,自己可以定义线程工厂生产想要的线程
第七个参数 拒绝策略 线程忙,而且任务队列满的时候,要执行的拒绝策略
拒绝策略:

  1. Abort 抛异常
  2. Discard 扔掉,不抛异常
  3. DiscardOldest 扔掉排队时间最久的
  4. CallerRuns 调用者处理任务
  5. 一般情况下都是自定义

定义线程池

package character07.ThreadPool;
/*
 * @Auther  laimouren
 */

import java.io.IOException;
import java.util.concurrent.*;

public class T05_00_HelloThreadPool {

    static class Task implements Runnable {
        private int i;

        public Task(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " Task " + i);
            try {
           		//阻塞
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "i=" + i +
                    '}';
        }
    }

    public static void main(String[] args) {

        //ThreadPool 维护着两个内容 一个是线程队列 另外一个是任务队列
        //线程池7个参数
        //corePoolSize 核心线程数
        //maxmumPoolSize 最大线程数
        //keepAliveTime 空闲时间 如果空闲时间线程没有干活 将归还给操作系统
        //第五个参数 BlockingQueue 阻塞队列 看源码 ThreadPoolExecutor()构造方法 BlockingQueue<Runnable> workQueue
        //第六个参数 默认的线程工厂
        //第七个参数 拒绝策略 线程忙 而且任务队列满的时候 要执行的拒绝策略
        //拒绝策略有 Abort 抛异常 Discard 扔掉 DiscardOldest 扔掉排队时间最久的 CallerRuns 调用者处理任务
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4,
                60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(4),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i < 8; i++) {
            tpe.execute(new Task(i));
        }

        System.out.println(tpe.getQueue());

        tpe.execute(new Task(100));

        System.out.println(tpe.getQueue());

        tpe.shutdown();
    }
}

ForkJoinPool

分解汇总的任务
用很少的线程可以执行很多的任务(子任务)ThreadPoolExecutor做不到先执行子任务
CPU密集型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值