Java-Concurrency
Actually we’ve learned the concept about multithread and the problem may cause.For instance, deadlock.
Following is some notes about the avoiding or solving the deadlock.
**Monitor **
At the beginning, we can look at a picture:
而一个锁就像一种任何时候只允许一个线程拥有的特权.
一个线程可以允许多次对同一对象上锁.对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁,没被锁的对象的计数器是0,线程每加锁一次,计数器就加1,每释放一次,计数器就减1.当计数器跳到0的 时候,锁就被完全释放了.
java虚拟机中的一个线程在它到达监视区域开始处的时候请求一个锁.JAVA程序中每一个监视区域都和一个对象引用相关联.
The program is like a building. And it stores some data meanwhile. But every time this building can only be occupied by only one thread.
If the thread enter this building, it’s called enter monitor;
If the thread enter the special room in this building, it’s called get monitor;
If the thread occupy the room, it’s called occupy monitor;
If the thread leave the room, it’s called release monitor;
If the thread leave the building, it’s called exit monitor;
Then,a LOCK is an authority only for single thread in every time. Single thread is allowed to multiplically add the lock to the same object.As for an object, JVM maintain a counter to record how many times the object was added lock.
In Java, to implement a monitor, we’re supposed to use Lock and Condition class,
Semaphore
In *** official docs ***:
A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource. For example, here is a class that uses a semaphore to control access to a pool of items:
class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// Not a particularly efficient data structure; just for demo
protected Object[] items = ... //whatever kinds of items being managed
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else
return false;
}
}
return false;
}
}
ThreadLocal
该修饰符主要修饰变量,使该变量变为线程局部变量,同一个ThreadLocal所包含的对象,在不同thread中有不同的副本 所以可以引出:
- 每个Thread有不同副本,所以其他thread不可访问,就不会有线程问题
- 因为只在一个线程内使用,其一般会被private static修饰; static主要是因为其保证了多个实例只会有一个,否则同一个线程可能会访问同一个类的不同实例,即使不错误也会导致浪费(重复创建了一样的对象)//????
结构
其内有一个 ThreadlocalMap的内部类,使用的是线性探测法(够慢,不过也够) 它的key为ThreadLocal对象,而且还是弱引用
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
//....
}
注意
ThreadLocal是个浅copy,如果变量是一个引用类型,那么就要考虑其内部状态是否会被改变,想要解决只能通过重写initialValue()方法来自己实现深copy; 其思路和锁也不一样,锁是强调如何同步多个线程去正确共享一个变量,而threadlocal是为了解决同一个变量如何不被多个线程共享;
使用场景:
- 每个线程需要有自己单独的实例
- 实例需要在多个方法中共享,但不希望被多线程共享
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!