Thinking in Java:第二十一章-并发

本文介绍并发编程的基本概念,包括任务定义、使用Executor执行器管理和执行任务、处理带返回值的任务、解决线程间的资源共享问题以及线程协作的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1:概述:对于某些问题,能够并发的执行程序中的多个部分,则会变得非常方便甚至非常必要
2:并发的多面性:为了使程序运行的更快,你必须学会如何利用这些额外的处理器,而这正是并发赋予你的能力。从性能的角度来说,如果没有任务会被阻塞,那么在单处理器中使用并发就没有任何意义。
3: 定义任务:LiftOff
/**
 * Created By Percy Gauguin On 2018/2/6
 * 定义任务:线程可以驱动任务,因此需要顶一种描述任务的方式,这可以由Runnable接口提供
 */
public class LiftOff implements Runnable {

    protected int countDown = 10;
    private static int taskCount = 0;
    private final int id = taskCount ++;

    public LiftOff() {
    }

    public LiftOff(int countDown) {
        this.countDown = countDown;
    }

    public String status() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + ")";
    }

    @Override
    public void run() {
        while (countDown -- > 0) {
            System.out.println(status());
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        // 当Runnable接口中导出一个类时,其中的run()方法并无特殊之处,她不会产生任何内在的线程能力
        // 要实现线程行为,必须显式地将一个任务附着到线程上,如...
        LiftOff launch = new LiftOff();
        launch.run();

        // 如...
        // 程序中会“同时”运行两个方法, main(), LiftOff.run() 是程序中与其他线程“同时”执行的代码。
        // 所以会出现LiftOff.run() 还没有执行完,就打印waiting for liftoff。
        Thread t = new Thread(new LiftOff());
        t.start();
        System.out.println("waiting for liftoff");
    }

}
4:使用Executor执行器:CacheThreadPool
/**
 * Created By Percy Gauguin On 2018/2/6
 * java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化并发编程。
 */
public class CacheThreadPool {
    public static void main(String[] args) throws InterruptedException {
        //ExecutorService es = Executors.newCachedThreadPool();

        //ExecutorService es = Executors.newFixedThreadPool(5);

        // SingleThreadExecutor就像是线程数量为1的FixedThreadPool。
        // newSingleThreadExecutor会序列化所有提交给它的任务,并且维护自己的悬挂任务队列。
        ExecutorService es = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 5; i++) {
            es.execute(new LiftOff());
        }
        TimeUnit.SECONDS.sleep(1

        );
        es.shutdown();
    }
}
5:带返回值的任务 Callable<V>接口:TaskWithResult
public class TaskWithResult implements Callable<String> {

    private int id;

    public TaskWithResult(int id) {
        this.id = id;
    }

    @Override
    public String call() {
        return "result of TaskWithResult " + id;
    }

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        List<Future<String>> futures = new ArrayList<Future<String>>();
        for (int i = 0; i < 10; i++) {
            // 这里使用的是submit()
            futures.add(es.submit(new TaskWithResult(i)));
        }
        for (Future<String> fs : futures) {
            try {
                // get() blocks util completion
                System.out.println(fs.get());
            }
            catch (InterruptedException e){
                System.out.println(e);
                return;
            }
            catch (ExecutionException e) {
                System.out.println(e);
                return;
            }
            finally {
                es.shutdown();
            }
        }
    }
}
6:最好把线程组看成是一次不成功的额尝试,你只要忽略它就好了。
7:解决共享资源竞争:读与写的同步。基本上所有的并发模式在解决线程冲突问题时,都是采用序列化共享资源的方案,这意味着在给定的时刻只允许一个任务访问共享资源。
lock包
8:可视性问题远比原子性问题复杂的多,一个任务做出的修改,即使在不中断的意义上是原子性的,对其他任务来说也可能是不可视的,(例如,修改知识暂时的存储在本地处理器的缓存中),因此不同的任务对应用的状态有不同的试图。同步机制强调在处理器系统中,一个任务做出的修改必须在应用中是可视的。volatile关键字可以保证应用中的可视性,如果将一个域声明为volatile的,那么只要对这个域产生了写操作,那么所有的读操作都可以看到这个修改,即使使用了本地缓存也是如此,volatile域会立即被写到主存中,而读取操作就发生在主存中。如果多个任务同时访问某个域,那么这个域应该是volatile的,否则,这个域就应该经由同步来访问,同步也会导致向主存中刷新,因此,如果一个域完全由synchronize方法或者语句块来防护,那就不需要将其设置volatile(所以不是很清楚volatile的作用。)
/**
 * Created By Percy Gauguin On 2018/2/6
 * volatile能保证所修饰域的可视性,但是不能保证线程安全
 */
public class SerialNumberGenerator {
    // volatile不能对递增不是原子操作这一事实产生影响。
    private static volatile int serialNumber = 0;

    // note,this ++ operation is not thread-safe
    // it will be thread-safe with synchronized
    public static int nextSerialNumber() {
        return serialNumber ++;
    }
}
class CircularSet {
    private int[] array;
    private int len;
    private int index = 0;

    public CircularSet(int len) {
        this.len = len;
        array = new int[len];
        // Initialize to a value not produced by the SerialNumberGenerator
        for (int i = 0; i < len; i++) {
            array[i] = -1;
        }
    }

    public synchronized void add(int i) {
        array[index] = i;
        index = (++ index) % len;
    }

    public synchronized boolean contains(int val) {
        for (int i = 0; i < len; i++) {
            if (array[i] == val) {
                return true;
            }
        }
        return false;
    }
}

public class SerialNumberChecker {
    private static final int SIZE = 10;
    private static CircularSet serials = new CircularSet(1000);
    private static ExecutorService es = Executors.newCachedThreadPool();

    static class SerialChecker implements Runnable {
        @Override
        public void run() {
            while (true) {
                int serial = SerialNumberGenerator.nextSerialNumber();
                if (serials.contains(serial)) {
                    System.out.println("duplicate: " + serial);
                    System.exit(0);
                }
                serials.add(serial);
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < SIZE; i++) {
            es.execute(new SerialChecker());
        }
    }
}
9:线程协作
/**
 * Created By Percy Gauguin On 2018/2/7
 * 线程协作
 */
class Car {
    private boolean waxOn = false;
    public synchronized void waxed() {
        waxOn = true;
        notifyAll();
    }

    public synchronized void buffed() {
        waxOn = false; // ready for another coat or wax
        notifyAll();
    }

    // buff完了之后调用,等待wax,不能继续buff
    public synchronized void waitForWaxing() throws InterruptedException {
        while (waxOn == false) {
            wait();
        }
    }
    // waxOn完了之后调用,等待buff,不能继续wax
    public synchronized void waitForBuffing() throws InterruptedException {
        while (waxOn == true) {
            wait();
        }
    }
}

class WaxOn implements Runnable {
    private Car car;

    public WaxOn(Car car) {
        this.car = car;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                System.out.println("wax on !");
                TimeUnit.MILLISECONDS.sleep(200);
                car.waxed();
                car.waitForBuffing();
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class WaxOff implements Runnable {
    private Car car;

    public WaxOff(Car car) {
        this.car = car;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                System.out.println("wax off !");
                TimeUnit.MILLISECONDS.sleep(200);
                car.buffed();
                car.waitForWaxing();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class WaxOMatic {
    public static void main(String[] args) throws InterruptedException {
        Car car = new Car();
        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new WaxOn(car));
        es.execute(new WaxOff(car));
        TimeUnit.SECONDS.sleep(5);
        es.shutdown();
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值