共享对象

  1. 可见性
    在没有同步的情况下,共享变量(错误的做法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package net.jcip.examples;

public class NoVisibility {
private static boolean ready;
private static int number;

private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}

public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
```
* 重排序

非线程安全可变整数的访问器:

```java
package net.jcip.examples;

import net.jcip.annotations.*;


@NotThreadSafe
public class MutableInteger {
private int value;

public int get() {
return value;
}

public void set(int value) {
this.value = value;
}
}
```
线程安全可变整数的访问器:

```java
package net.jcip.examples;

import net.jcip.annotations.*;

@ThreadSafe
public class SynchronizedInteger {
@GuardedBy("this") private int value;

public synchronized int get() {//TODO 不仅仅要有setter还要有getter
return value;
}

public synchronized void set(int value) {
this.value = value;
}
}
  • volatile
    同步的弱形式,仅仅可见,而且对它的操作不会与其他的内存操作一起被重排序,volatile变量不会缓存中寄存器或缓存在其他处理器隐藏的地方,所以读取一个volatile变量,总是会返回有某一个线程所写入的最新值,但是volatile不会阻塞。
    一个很好的例子,数羊🐑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package net.jcip.examples;

public class CountingSheep {
volatile boolean asleep;

void tryToSleep() {
while (!asleep)
countSomeSheep();
}

void countSomeSheep() {
// One, two, three...
}
}
```

2. 发布和溢出
发布对象:

```java
package net.jcip.examples;

class Secrets {
public static Set<Secret> knownSecrets;

public void initialize() {
knownSecrets = new HashSet<Secret>();
}
}

class Secret {
}

允许内部可变的数据溢出(不要这样做) :

1
2
3
4
5
6
7
8
9
10
11
package net.jcip.examples;

class UnsafeStates {
private String[] states = new String[]{
"AK", "AL" /*...*/
};

public String[] getStates() {
return states;
}
}

隐式的运行this溢出(不要这样做):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package net.jcip.examples;

public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}

void doSomething(Event e) {
}


interface EventSource {
void registerListener(EventListener e);
}

interface EventListener {
void onEvent(Event e);
}

interface Event {
}
}

```
使用工厂方法防止this引用在构造期间溢出:
```java

package net.jcip.examples;

public class SafeListener {
private final EventListener listener;

private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
};
}

public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}

void doSomething(Event e) {
}


interface EventSource {
void registerListener(EventListener e);
}

interface EventListener {
void onEvent(Event e);
}

interface Event {
}
}

栈限制:

package net.jcip.examples;

import java.util.*;

public class Animals {
    Ark ark;
    Species species;
    Gender gender;

    public int loadTheArk(Collection<Animal> candidates) {
        SortedSet<Animal> animals;
        int numPairs = 0;
        Animal candidate = null;

        // animals confined to method, don't let them escape!
        animals = new TreeSet<Animal>(new SpeciesGenderComparator());
        animals.addAll(candidates);
        for (Animal a : animals) {
            if (candidate == null || !candidate.isPotentialMate(a))
                candidate = a;
            else {
                ark.load(new AnimalPair(candidate, a));
                ++numPairs;
                candidate = null;
            }
        }
        return numPairs;
    }


    class Animal {
        Species species;
        Gender gender;

        public boolean isPotentialMate(Animal other) {
            return species == other.species && gender != other.gender;
        }
    }

    enum Species {
        AARDVARK, BENGAL_TIGER, CARIBOU, DINGO, ELEPHANT, FROG, GNU, HYENA,
        IGUANA, JAGUAR, KIWI, LEOPARD, MASTADON, NEWT, OCTOPUS,
        PIRANHA, QUETZAL, RHINOCEROS, SALAMANDER, THREE_TOED_SLOTH,
        UNICORN, VIPER, WEREWOLF, XANTHUS_HUMMINBIRD, YAK, ZEBRA
    }

    enum Gender {
        MALE, FEMALE
    }

    class AnimalPair {
        private final Animal one, two;

        public AnimalPair(Animal one, Animal two) {
            this.one = one;
            this.two = two;
        }
    }

    class SpeciesGenderComparator implements Comparator<Animal> {
        public int compare(Animal one, Animal two) {
            int speciesCompare = one.species.compareTo(two.species);
            return (speciesCompare != 0)
                    ? speciesCompare
                    : one.gender.compareTo(two.gender);
        }
    }

    class Ark {
        private final Set<AnimalPair> loadedAnimals = new HashSet<AnimalPair>();

        public void load(AnimalPair pair) {
            loadedAnimals.add(pair);
        }
    }
}

ThreadLocal:

package net.jcip.examples;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * ConnectionDispenser
 * <p/>
 * Using ThreadLocal to ensure thread confinement
 *
 * @author Brian Goetz and Tim Peierls
 */
public class ConnectionDispenser {
    static String DB_URL = "jdbc:mysql://localhost/mydatabase";

    private ThreadLocal<Connection> connectionHolder
            = new ThreadLocal<Connection>() {
                public Connection initialValue() {
                    try {
                        return DriverManager.getConnection(DB_URL);
                    } catch (SQLException e) {
                        throw new RuntimeException("Unable to acquire Connection, e");
                    }
                };
            };

    public Connection getConnection() {
        return connectionHolder.get();
    }
}
  1. 不可变性
package net.jcip.examples;

import java.util.*;

import net.jcip.annotations.*;

@Immutable
 public final class ThreeStooges {
    private final Set<String> stooges = new HashSet<String>();

    public ThreeStooges() {
        stooges.add("Moe");
        stooges.add("Larry");
        stooges.add("Curly");
    }

    public boolean isStooge(String name) {
        return stooges.contains(name);
    }

    public String getStoogeNames() {
        List<String> stooges = new Vector<String>();
        stooges.add("Moe");
        stooges.add("Larry");
        stooges.add("Curly");
        return stooges.toString();
    }
}

安全的发布对象:
1、 通过静态初始化器初始化对象的引用。
2、将它的引用存储到volatile域或AtomicReference
3、将它的引用存储到正确创建的对象的final域中(创建期间没有发生 this 引用的溢出)。
4、将它的引用存储到由锁正确保护的域中。
线程安全容器内的同步,意味着将对象放入这些容器,就保证了安全