【Java基础】并发

你离开我真会死。 提交于 2020-03-12 16:41:16

Num1:同步访问共享的可变数据

关键字Synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法,或者某一个代码块。、

同步不仅仅理解为互斥的方式,如果没有同步,一个线程的变化就不能被其他线程看到。同步不仅可以阻止一个线程看到对象处于不一致的状态中,它还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前的所有修改效果。

基本版本:

public class StopThread {
    private static boolean stopRequested;

    private static synchronized void requestStop() {
        stopRequested = true;
    }

    private static synchronized boolean stopRequested() {
        return stopRequested;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested())
                    i++;
            }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        requestStop();
    }
}

改善版本:

public class StopThread {
    private static volatile boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested)
                    i++;
            }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

简而言之,当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步。如果没有同步,就无法保证一个线程所做的修改可以被另一个线程获知,未能同步共享可变的数据或造成程序的活性失败和安全性失败。

Num2:executor和task优先于线程

如何创建一个工作队列呢,一行代码。

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown();

如果想让不止一个线程来处理来自这个队列的请求,只要调用一个不同的静态工厂,这个工厂创建了一种不同的executor service,称作线程池(thread pool)

Num3:慎用延迟初始化

延迟初始化是延迟到需要域的是值时才将它初始化的这种行为。如果永远不需要这个值,这个域就永远不会被初始化。这种方法既适用于静态域,也适用于实例域。虽然延迟初始化主要是一种优化,但它也可以用来打破类和实例初始化的有害循环。

  • 在大多数情况下,正常的初始化要优先于延迟初始化。

  • 如果利用延迟优化来破坏初始化的循环,就要使用同步的访问方法。
  • 如果出于性能的考虑而需要对静态域使用延迟初始化,就用lazy initialization holder class 模式。
  • 如果出于性能的考虑而需要对实例域使用延迟初始化,就用双重检查模式double-check idiom
  • 单重检查模式single-check idiom

示例代码:

public class Initialization {

    // Normal initialization of an instance field - Page 282
    private final FieldType field1 = computeFieldValue();

    // Lazy initialization of instance field - synchronized accessor - Page 282
    private FieldType field2;

    synchronized FieldType getField2() {
        if (field2 == null)
            field2 = computeFieldValue();
        return field2;
    }

    // Lazy initialization holder class idiom for static fields - Page 283
    private static class FieldHolder {
        static final FieldType field = computeFieldValue();
    }

    static FieldType getField3() {
        return FieldHolder.field;
    }

    // Double-check idiom for lazy initialization of instance fields - Page 283
    private volatile FieldType field4;

    FieldType getField4() {
        FieldType result = field4;
        if (result == null) { // First check (no locking)
            synchronized (this) {
                result = field4;
                if (result == null) // Second check (with locking)
                    field4 = result = computeFieldValue();
            }
        }
        return result;
    }

    // Single-check idiom - can cause repeated initialization! - Page 284
    private volatile FieldType field5;

    private FieldType getField5() {
        FieldType result = field5;
        if (result == null)
            field5 = result = computeFieldValue();
        return result;
    }

    private static FieldType computeFieldValue() {
        return new FieldType();
    }
}

class FieldType {
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!