JUC笔记(How)

JUC笔记(How)

三、How

线程创建和使用

	// 第四种:使用线程池来创建线程
    @Test
    public void test04(){
        ExecutorService service = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                2,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3)
        );
        for (int i = 0; i < 10; i++) {
            service.submit(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }

        service.shutdown();
    }

    // 第三种:实现Callable接口来实现线程创建 : 可以有返回值、进行管理
    @Test
    public void test03() throws ExecutionException, InterruptedException {
        class Test03 implements Callable<String> {
            @Override
            public String call() {
                return "1";
            }
        }
        Test03 test03 = new Test03();
        FutureTask<String> ft=new FutureTask<>(test03);
        //FutureTask实现了Runnable接口所以可以传入
        Thread t=new Thread(ft);
        t.start();
        System.out.println(ft.get());
    }

    // 第二种:实现Runable接口来实现线程创建
    @Test
    public void test02(){
        class Test02 implements Runnable{
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("执行了run方法");
                }
            }
        }
        new Thread(new Test02()).start();
    }

    // 第一种:继承Thread类来实现线程创建
    @Test
    public void test01(){
        class Test01 extends Thread{
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("执行了run方法");
                }
            }
        }
        new Test01().start();
    }

volatile关键字的使用

public class Demo01 {
    private static volatile int num = 0;

    // 三、禁止指令重排

    /**
     * 指令重排:程序运行时的样子不是你所理想型的样子,在不影响程序结果的前提下,指令执行的顺序可以进行调换。
     *
     * 初始化参数:a、b、x、y都为0
     * 指令重排前的样子:
     * 线程A:x = a;b = 1;
     * 线程B:y = b;a = 2;
     * 结果:x = 0;y = 0;
     *
     * 指令重排后的样子:
     * 线程A:b = 1;x = a;
     * 线程B:a = 2;y = b;
     * 结果:x = 2;y = 1;
     *
     */

    // 使用AtomicInteger保持原子性
    AtomicInteger atomicInteger = new AtomicInteger(0);
    // 二、不保持原子性
    @Test
    public void test02(){
        for (int i = 0; i < 10; i++) {
            new Thread(()->num++).start();
        }
        System.out.println(num);
        // 保持原子性
        for (int i = 0; i < 10; i++) {
            new Thread(()->atomicInteger.getAndIncrement()).start();
        }

        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(atomicInteger.get());

    }

    // 一、保持可见性

    /**
     * 线程有单独的工作内存
     */
    @Test
    public void test01(){
        new Thread(()-> {while(num == 0){}}).start();
        num++;
        System.out.println(num);
    }
}

Lock锁的使用

// 生产者与消费者
public class Demo01 {
    public static void main(String[] args){
        ProductionAndConsumption pac = new ProductionAndConsumption();
        for (int i = 0; i < 10; i++) {
            new Thread(()->pac.getNumber()).start();
        }
        for (int i = 10; i < 20; i++) {
            new Thread(()->pac.setNumber()).start();
        }

    }
}
class ProductionAndConsumption{
    private int number = 0;

    public Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void setNumber(){
        lock.lock();
        try{
            while (number == 1){
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.printf(Thread.currentThread().getName()+"\t生产\t库存: %s\n",++number);
            condition.signalAll();
        }catch(Exception e){
           e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void getNumber(){
        lock.lock();
        try{
            while (number == 0){
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.printf(Thread.currentThread().getName()+"\t消费\t\t库存: %s\n",--number);
            condition.signalAll();
        }catch(Exception e){
           e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
//		synchronized方式
//    public synchronized void setNumber(){
//        while (number == 1){
//            try {
//                wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//        System.out.printf(Thread.currentThread().getName()+"\t生产\t库存: %s\n",++number);
//        notifyAll();
//    }
//
//    public synchronized void getNumber(){
//        while (number == 0){
//            try {
//                wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//        System.out.printf(Thread.currentThread().getName()+"\t消费\t\t库存: %s\n",--number);
//        notifyAll();
//    }
}

ForkJoin的使用

public class SumTask extends RecursiveTask<Long> {
    public static void main(String[] args){
        // 创建随机数组成的数组:
        long[] array = new long[400];
        for (int i = 0; i < array.length; i++) {
            array[i] = new Random().nextInt(1000);
        }
        // fork/join task:
        ForkJoinPool fjp = new ForkJoinPool(4); // 最大并发数4
        ForkJoinTask<Long> task = new SumTask(array, 0, array.length);
        long startTime = System.currentTimeMillis();
        Long result = fjp.invoke(task);
        long endTime = System.currentTimeMillis();
        System.out.println("Fork/join sum: " + result + " in " + (endTime - startTime) + " ms.");
    }

    static final int THRESHOLD = 100;
    long[] array;
    int start;
    int end;

    SumTask(long[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        if (end - start <= THRESHOLD) {
            // 如果任务足够小,直接计算:
            long sum = 0;
            for (int i = start; i < end; i++) {
                sum += array[i];
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(String.format("compute %d~%d = %d", start, end, sum));
            return sum;
        }
        // 任务太大,一分为二:
        int middle = (end + start) / 2;
        System.out.println(String.format("split %d~%d ==> %d~%d, %d~%d", start, end, start, middle, middle, end));
        SumTask subtask1 = new SumTask(this.array, start, middle);
        SumTask subtask2 = new SumTask(this.array, middle, end);
        invokeAll(subtask1, subtask2);
        Long subresult1 = subtask1.join();
        Long subresult2 = subtask2.join();
        Long result = subresult1 + subresult2;
        System.out.println("result = " + subresult1 + " + " + subresult2 + " ==> " + result);
        return result;
    }
}
上一篇:How Time Diary Use Data


下一篇:How to display a random picture from a folder?