Java多线程

1 使用线程池并选择合适的线程池类型,制订线程执行策略(最大线程数,等待数等),线程饱和策略,尽量使线程之间独立无依赖,可以使用Excetor的Future和Callable实现有返回的线程来实现线程之间的有赖性,线程的取消与关闭

http://blog.csdn.net/cutesource/archive/2010/08/04/5788534.aspx 文中使用的例子:

public class FutureRenderer {   
    private final ExecutorService executor = ...;   
    void renderPage(CharSequence source) {   
        final List<ImageInfo> imageInfos = scanForImageInfo(source);   
        Callable<List<ImageData>> task =  new Callable<List<ImageData>>() {   
                    public List<ImageData> call() {   
                        List<ImageData> result     = new ArrayList<ImageData>();   
                        for (ImageInfo imageInfo : imageInfos)   
                            result.add(imageInfo.downloadImage());   
                        return result;   
                    }   };   
        Future<List<ImageData>> future =  executor.submit(task);   
        renderText(source);   
        try {   
            List<ImageData> imageData =  future.get();   //得到返回结果
            for (ImageData data : imageData)   
                  renderImage(data);   
        } catch (InterruptedException e) {   
                      Thread.currentThread().interrupt();    // Re-assert the thread's interrupted status   
                      future.cancel(true);     // We don't need the result, so cancel the task too   
        } catch (ExecutionException e) {   
            throw launderThrowable(e.getCause());   
        }   
    }   
}

评:ExecutorService 是Executor的子接口,Executor的执行方法Executor.execute(RunnableTask);  ExecutorService 有一个子接口ScheduledExecutorSerivice,此接口用于定时任务,非常方便!如ScheduledExecutorSerivice.scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUint uint)等。ExecutorService的典型用法是ExecutorService.submit(Callable<T> task)用于执行一个具有返回结果的值,返回Future<T>,可以通过此future.get得到此T。

 

Executors: Factory and utility methods for Executor, ExecutorService,ScheduledExecutorService,ThreadFactory, andCallable classes defined in this package. This class supports the following kinds of methods:

  • Methods that create and return an ExecutorService set up with commonly useful configuration settings.
  • Methods that create and return a ScheduledExecutorService set up with commonly useful configuration settings.
  • Methods that create and return a "wrapped" ExecutorService, that disables reconfiguration by making implementation-specific methods inaccessible.
  • Methods that create and return a ThreadFactory that sets newly created threads to a known state.
  • Methods that create and return a Callable out of other closure-like forms, so they can be used in execution methods requiringCallable

而ExecutorService is An Executor that provides methods to manage termination and methods that can produce aFuture for tracking progress of one or more asynchronous tasks. AnExecutorService can be shut down, which will cause it to stop accepting new tasks. After being shut down, the executor will eventually terminate, at which point no tasks are actively executing, no tasks are awaiting execution, and no new tasks can be submitted.

class NetworkService {
    private final ServerSocket serverSocket;
    private final ExecutorService pool;

    public NetworkService(int port, int poolSize) throws IOException {
      serverSocket = new ServerSocket(port);
      pool = Executors.newFixedThreadPool(poolSize);//注意Executors可以得到诸多Executor,ExecutorService和ScheduledExecutorService等,此处和Collections工具类与Collection用法相同。
    }

    public void serve() {
      try {
        for (;;) {
          pool.execute(new Handler(serverSocket.accept()));
        }
      } catch (IOException ex) {
        pool.shutdown();
      }
    }
  }

  class Handler implements Runnable {
    private final Socket socket;
    Handler(Socket socket) { this.socket = socket; }
    public void run() {
      // read and service request
    }
}

What a lock?  the lock technology is used to synchronize simultaneous threads to be waiting on a queue for the current thread to release the lock. in the program it is very important to notice the scope of the lock and object be locked, these two points represent in several ways such as synchronized on class/instance methods, the synchronized block.  All variable fields could be affected by several threads simultaneously should be synchronized no matter what the variable type is. 

2 死锁发生的条件,怎样避免,如何检测?死锁发生的典型情景是两个线程互相等待彼此释放的资源,如syschronized(obj1){syschronized(obj2){}}。可使用工具Thread dump工具进行检测。如何避免死锁?

          (1)尽量不要在释放锁前在竞争其他锁(2)制订获取锁的顺序机制策略(3)使用定时锁:超时不再堵塞任务,而是放弃此任务,定时锁属于显示锁(4)减少锁粒度,使用显示锁:Lock(5)用读写锁代替整个对象锁。所谓对象锁就是指使用Synchronized修饰的对象及方法是将整个对象或类都加了锁,粒度很大。

  http://blog.csdn.net/cutesource/archive/2010/08/05/5790888.aspx

疑问:以下为上文中引用:

public class StripedMap {   
    // Synchronization policy: buckets[n] guarded by locks[n%N_LOCKS]   
    private static final int N_LOCKS = 16;   
    private final Node[] buckets;   
    private final Object[] locks;   
    private static class Node { ... }   
    public StripedMap(int numBuckets) {   
        buckets = new Node[numBuckets];   
        locks = new Object[N_LOCKS];   
        for (int i = 0; i < N_LOCKS; i++)   
            locks[i] = new Object();   
    }   
    private final int hash(Object key) {   
        return Math.abs(key.hashCode() % buckets.length);   
    }   
    public Object get(Object key) {   
        int hash = hash(key);   
        synchronized (locks[hash % N_LOCKS]) {   
            for (Node m = buckets[hash]; m != null; m = m.next)   
                if (m.key.equals(key))   
                    return m.value;   
        }   
        return null;   
    }   
      ...   
}  

上面这个例子是通过hash算法来把存取的值所对应的hash值来作为锁,这样就只需要对hash值相同的对象存取串行化,而不是像HashTable那样对任何对象任何操作都串行化。这一句不太明白,不过这样的用法实在是太棒了!可以创建一定数量的空对象放到一个数组中,然后根据对对象的key值从这个空对象数组中获取一个对象锁。但这种方式只能用于所要同步的线程根据对象值线程不同的情况。如果要同步所有的对象,则此方法无效,另,同步时可以使用byte[] b=new byte[],这样一个空byte数组来放到sychronized的同步块中,byte[]比一个空对象占用空间小。

定时锁的那个例子不全,基本上时使用java.util.concurrent.locks.ReentrantLock类中的tryLock(long timeout, TimeUnit unit),如果该锁没有在timeout时间内没有被获取到放弃此锁。reentrantLock的典型用法如下:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...
   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
}

ReentrantLock: a reetrantlock is the mutual exclusion lock with same basic behavior as the implicit monitor lock  accessed using synchronized methods and statements, but with more extended capability.  A reentrantlock is owned by the thread last successfully locking but not yet unlocking it. Checking via isHeldByCurrentThread() and getHoldCount() , and it could check the waitingQues with the getQueuedThreads, length, whethter the lock is fair, and whether a thread is contained in the waiting queue, and tryLock(long timeout, TImeunit) to acquire the lock in the most time. 


以下为读写锁接口的JDK说明。ReadWriteLock的具体子类为ReentrantReadWriteLock

 

public interface ReadWriteLock

A ReadWriteLock maintains a pair of associated locks(读写锁是成对的), one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. Thewrite lock is exclusive.

A read-write lock allows for a greater level of concurrency in accessing shared data than that permitted by a mutual exclusion lock. It exploits the fact that while only a single thread at a time (awriter thread) can modify the shared data, in many cases any number of threads can concurrently read the data (hencereader threads). In theory, the increase in concurrency permitted by the use of a read-write lock will lead to performance improvements over the use of a mutual exclusion lock. In practice this increase in concurrency will only be fully realized on a multi-processor, and then only if the access patterns for the shared data are suitable.

 

Java 5提供了一个读写分离锁(ReadWriteLock)来实现读-读并发,读-写串行,写-写串行的特性。这种方式更进一步提高了可并发性,因为有些场景大部分是读操作,因此没必要串行工作。关于ReadWriteLock的具体使用可以参加一下示例:

[java]  view plain copy
  1. public class ReadWriteMap<K,V> {  
  2.     private final Map<K,V> map;  
  3.     private final ReadWriteLock lock = new ReentrantReadWriteLock();  
  4.     private final Lock r = lock.readLock();  
  5.     private final Lock w = lock.writeLock();  
  6.     public ReadWriteMap(Map<K,V> map) {  
  7.         this.map = map;  
  8.     }  
  9.     public V put(K key, V value) {  
  10.         w.lock();  
  11.         try {  
  12.             return map.put(key, value);  
  13.         } finally {  
  14.             w.unlock();  
  15.         }  
  16.     }  
  17.     // Do the same for remove(), putAll(), clear()  
  18.     public V get(Object key) {  
  19.         r.lock();  
  20.         try {  
  21.             return map.get(key);  
  22.         } finally {  
  23.             r.unlock();  
  24.         }  
  25.     }  
  26.     // Do the same for other read-only Map methods  
  27. }  

Sample usages. Here is a code sketch showing how to perform lock downgrading after updating a cache (exception handling is particularly tricky when handling multiple locks in a non-nested fashion):

 class CachedData {
   Object data;
   volatile boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        try {
          // Recheck state because another thread might have
          // acquired write lock and changed state before we did.
          if (!cacheValid) {
            data = ...
            cacheValid = true;
          }
          // Downgrade by acquiring read lock before releasing write lock
          rwl.readLock().lock();
        } finally  {
          rwl.writeLock().unlock(); // Unlock write, still hold read
        }
     }

     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }
ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. This is typically worthwhile only when the collections are expected to be large, accessed by more reader threads than writer threads, and entail operations with overhead that outweighs synchronization overhead.

3 Java中的并发工具:(1)同步容器类,如List中的Vector,Map中的HashTable,性能比较差(2)并发容器类,List中CopyOnWriteArrayList,Map中ConcurrentHashMap(3)生产者和消费者模式(4)阻塞和可中断方法(5)sychronizer

http://blog.csdn.net/cutesource/archive/2010/08/01/5780740.aspx其中生产者与消费者中引用了LinkedBlockingQueue,中的put方法,关于linkedBlockingQueue的完全代码见http://www.docjar.com/html/api/java/util/concurrent/LinkedBlockingQueue.java.html。LInkedBlockingQueue通过在其实现的代码中加上了锁、同步等机制使生产者和消费者的实现中不必考虑线程的同步,生产者消费者模式的实现就是生产者和消费者线程共享同一个LinkedBlockingQueue,然后生产者线程使用LinkedBlockingQueue的put方法,而消费者线程使用LinkedBlockingQueue中的take方法。

想到了Thread.interrupted()和Thread.isterrupted()方法,两者都是判断当前线程是否被interrupted,但前者会将线程的状态清除,后者不会。

4 为了能让开发人员安全正确地在Java存储模型上编程,JVM提供了一个happens-before原则:

•在程序顺序中, 线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
•对象监视器的解锁发生在等待获取对象锁的线程之前.
•对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
•对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
•线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前.
有了原则还不够,Java提供了以下工具和方法来保证变量的可见性和安全发布:

•使用 synchronized来同步变量初始化。此方式会立马把工作内存中的变量同步到主内存中
•使用 volatile关键字来标示变量。此方式会直接把变量存在主存中而不是工作内存中 

•could use the wait() and notify() method of the object to synchronize

•final变量。常量内也是存于主存中
另外,一定要明确只有共享变量才会有以上那些问题


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cutesource/archive/2010/08/01/5780486.aspx

http://blog.csdn.net/cutesource/archive/2010/08/01/5780486.aspx
 

A CountDownLatch is a versatile synchronization tool and can be used for a number of purposes. A CountDownLatch initialized with a count of one serves as a simple on/off latch, or gate: all threads invoking await wait at the gate until it is opened by a thread invoking countDown(), this mechanism will be used be as the Start single CountDownLatch. A CountDownLatch initialized to N can be used to make one thread wait until N threads have completed some action, or some action has been completed N times, this would be used as the completion single countdownlatch. 

Sample usage: Here is a pair of classes in which a group of worker threads use two countdown latches:

  • The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed;
  • The second is a completion signal that allows the driver to wait until all workers have completed.
 class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);

     for (int i = 0; i < N; ++i) // create and start threads
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // don't let run yet
     startSignal.countDown();      // let all threads proceed
     doSomethingElse();
     doneSignal.await();           // wait for all to finish
   }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
      this.startSignal = startSignal;
      this.doneSignal = doneSignal;
   }
   public void run() {
      try {
        startSignal.await();
        doWork();
        doneSignal.countDown();
      } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }

 

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;
   }

 }
 

Before obtaining an item each thread must acquire a permit from the semaphore, guaranteeing that an item is available for use. When the thread has finished with the item it is returned back to the pool and a permit is returned to the semaphore, allowing another thread to acquire that item. Note that no synchronization lock is held when acquire() is called as that would prevent an item from being returned to the pool. The semaphore encapsulates the synchronization needed to restrict access to the pool, separately from any synchronization needed to maintain the consistency of the pool itself.

A semaphore initialized to one, and which is used such that it only has at most one permit available, can serve as a mutual exclusion lock. This is more commonly known as a binary semaphore, because it only has two states: one permit available, or zero permits available. When used in this way, the binary semaphore has the property (unlike many Lock implementations), that the "lock" can be released by a thread other than the owner (as semaphores have no notion of ownership). This can be useful in some specialized contexts, such as deadlock recovery. 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值