线程

setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为Daemon模式,false为User模式。

这就是守护线程,守护着最后一个用户线程,如果没有用户线程了,他也没作用了,退出。

线程名,线程组,是否为守护线程

Future 接口允许表示已经完成的任务、正在执行过程中的任务或者尚未开始执行的任务。通过 Future 接口,可以尝试取消尚未完成的任务,查询任务已经完成还是取消了,以及提取(或等待)任务的结果值。  FutureTask 类实现了 Future,一些提交方法(如 ExecutorService.submit())除了提交任务之外,还将返回 Future 接口。    Future.get() 方法检索任务计算的结果(或如果任务完成,但有异常,则抛出 ExecutionException)。如果任务尚未完成,那么 Future.get() 将被阻塞,直到任务完成;如果任务已经完成,那么它将立即返回结果。

CyclicBarrier 类可以帮助同步,它允许一组线程等待整个线程组到达公共屏障点。

BlockingQueue:阻塞队列,该类主要提供了两个方法put()和take(),前者将一个对象放到队列中,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。

J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。

AtomicInteger:一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

 

package cn.php.test;

 

import java.util.concurrent.CountDownLatch;

/**

 *value++线程不安全示例和CountDownLatch的用法

 */

class Counter {

   private int value;

 

   public synchronized int increase() {

      return value++;

   }

 

   public int unSyncIncrease() {

      return value++;

   }

 

   public int get() {

      return value;

   }

}

 

public class Test4 {

   public static void main(String[] args) throws InterruptedException {

      long start = System.currentTimeMillis();

      final CountDownLatch latch = new CountDownLatch(100);

      final Counter counter = new Counter();

      for (int i = 0; i < 100; i++) {

        new Thread(new Runnable() {

 

           @Override

           public void run() {

              for (int i = 0; i < 100000; i++) {

                 counter.increase();

                 //counter.unSyncIncrease();

              }

              latch.countDown();

           }

        }).start();

      }

     

      latch.await();

      long end = System.currentTimeMillis();

      System.out.println("Elapsed: " + (end - start) + "ms, value=" + counter.get());

     

   }

}

 

package cn.php.test;

 

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.atomic.AtomicInteger;

/**

 *AtomicInteger线程安全示例和CountDownLatch的用法

 */

class Counter1 {

   private AtomicInteger value = new AtomicInteger();

 

   public  int increase() {

      return value.incrementAndGet();

   }

 

 

   public int get() {

      return value.get();

   }

}

 

public class Test5 {

   public static void main(String[] args) throws InterruptedException {

      long start = System.currentTimeMillis();

      final CountDownLatch latch = new CountDownLatch(100);

      final Counter1 counter = new Counter1();

      for (int i = 0; i < 100; i++) {

        new Thread(new Runnable() {

           @Override

           public void run() {

              for (int i = 0; i < 100000; i++) {

                 counter.increase();

              }

              latch.countDown();

           }

        }).start();

      }

     

      latch.await();

      long end = System.currentTimeMillis();

      System.out.println("Elapsed: " + (end - start) + "ms, value=" + counter.get());

     

   }

}

CountDownLatch是一个倒数计数的锁,当倒数到0时触发事件,也就是开锁,其他人就可以进入了。

使用Callable和Future实现线程等待和多线程返回值

package cn.php.test;

 

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

 

public class Test6 {

   public static void main(String[] args) throws InterruptedException,

        ExecutionException {

      System.out.println("start main thread");

      final ExecutorService exec = Executors.newFixedThreadPool(5);

      Callable<String> callable = new Callable<String>() {

        @Override

        public String call() throws Exception {

           System.out.println("  start new thread.");

           Thread.sleep(1000 * 5);

           System.out.println("  end new thread.");

           return "some value.";

        }

      };

      Future<String> future = exec.submit(callable);

      Thread.sleep(1000 * 2);

      System.out.println(future.get()); // 阻塞,并待子线程结束,

      exec.shutdown();

      exec.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

      System.out.println("end main thread");

   }

}

 

package cn.php.test;

 

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

 

public class Test6 {

   public static void main(String[] args) throws InterruptedException,

        ExecutionException {

      System.out.println("start main thread");

      final ExecutorService exec = Executors.newFixedThreadPool(5);

      List<Future<String>> tasks = new ArrayList<Future<String>>();

      for (int i = 0; i < 5; i++) {

        Callable<String> callable = new Callable<String>() {

           @Override

           public String call() throws Exception {

              System.out.println("  start new thread.");

              Thread.sleep(1000 * 5);

              System.out.println("  end new thread.");

              return "some value.";

           }

        };

        tasks.add(exec.submit(callable));

      }

      Thread.sleep(1000 * 2);

      for(Future<String> task:tasks){

        System.out.println(task.get()); //阻塞

      }

      exec.shutdown();

      exec.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

      System.out.println("end main thread");

   }

}

 

package cn.php.test;

 

import java.util.concurrent.Callable;

import java.util.concurrent.CompletionService;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorCompletionService;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

/**

 * CompletionService,它会首先取完成任务的线程.take() 获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。

 */

public class Test7 {

   public static void main(String[] args) throws InterruptedException,

        ExecutionException {

      ExecutorService pool = Executors.newFixedThreadPool(5);

      CompletionService<String> CompletionService = new ExecutorCompletionService<String>(

           pool);

      for (int i = 0; i < 5; i++) {

        final int no = i;

        Callable<String> callable = new Callable<String>() {

           @Override

           public String call() throws Exception {

              System.out.println("task" + no + "start");

              return "task" + no;

           }

        };

        CompletionService.submit(callable);

      }

      System.out.println("Show web content");

      for (int i = 0; i < 5; i++) {

        Future<String> task = CompletionService.take();

        String img = task.get();

        System.out.println(img);

      }

      System.out.println("End");

      // 关闭线程池

      pool.shutdown();

   }

}

 

 

Semaphore信号量

拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码

 

package cn.php.test;

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

 

/**

 * 拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码

 */

public class Test7 {

   public static void main(String[] args) {

      final Semaphore semp = new Semaphore(5);

      ExecutorService pool = Executors.newFixedThreadPool(10);

      for (int i = 0; i < 20; i++) {

        final int no = i;

        pool.submit(new Runnable() {

           @Override

           public void run() {

              try {

                 // 获取许可

                 semp.acquire();

                 System.out.println("Accessing" + no);

                 Thread.sleep((long) (Math.random() * 10000));

                 // 访问完后,释放

                 semp.release();

              } catch (InterruptedException e) {

                 e.printStackTrace();

              }

 

           }

        });

      }

      pool.shutdown();

   }

}

 

 

挂起的原因可能是如下几种情况:
     (1)通过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
     (2)通过调用join()方法使线程挂起,使自己等待另一个线程的结果,直到另一个线程执行完毕为止。
     (3)通过调用wait()方法使线程挂起,直到线程得到了notify()和notifyAll()消息,线程才会进入“可执行”状态。
     (4)使用suspend挂起线程后,可以通过resume方法唤醒线程。
      虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成死锁,因此,这两个方法被标识为 deprecated(抗议)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。

调用sleep()、yield()、suspend()的时候并没有被释放锁
      调用wait()的时候释放当前对象的锁

      wait()方法表示,放弃当前对资源的占有权,一直等到有线程通知,才会运行后面的代码。
      notify()方法表示,当前的线程已经放弃对资源的占有,通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复,然后继续运行wait()后面的语句。
 notifyAll()方法表示,当前的线程已经放弃对资源的占有,通知所有的等待线程从wait()方法后的语句开始运行。 

 

等待和锁实现资源竞争
      等待机制与锁机制是密切关联的,对于需要竞争的资源,首先用synchronized确保这段代码只能一个线程执行,可以再设置一个标志位condition判断该资源是否准备好,如果没有,则该线程释放锁,自己进入等待状态,直到接收到notify,程序从wait处继续向下执行。

  1. synchronized(obj) {

  2. while(!condition) {
  3. obj.wait();
  4. }
  5. obj.doSomething();
  6. }

以上程序表示只有一个线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A释放该锁,进入wait()。

      在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:

  1. synchronized(obj) {

  2. condition = true;
  3. obj.notify();

 

需要注意的是:
  # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
  # 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
  # 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
  # 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
  # obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
  # 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。

 

锁和唤醒:唤醒需要此锁的线程

 

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

线程总体分两类:用户线程和守候线程。
当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由操作系统或者用户自己创建的

 

thread.yield():yield()方法只是把线程的状态有执行状态打回可运行状态, ,并不保证下一个运行的线程就一定不是该线程, 以考虑用Thread.sleep(long millis);方法强制当前线程睡眠至少millis毫秒
 
Join()方法: 阻塞调用线程,直到某个线程终止或经过了指定时间为止 
Join的官方解释: 阻塞调用线程,直到某个线程终止或经过了指定时间为止 
Q:谁是调用线程?

A:Join代码写在那,哪个就是调用线程

Q:某个线程又是指的是谁? 
A:如本例thread1执行了Join方法,thread1为某个线程

join(long millis):执行Join方法的线程等待最长为 millis 毫秒

package cn.php.test;

 

class RunnerTest implements Runnable{

   int a =0;

   @Override

   public void run() {

      for(int i=0;i<5;i++){

        try {

           //Thread.sleep(10);

           Thread.sleep(10);

        } catch (InterruptedException e) {

           e.printStackTrace();

        }

        a=a+1;

      }

   }

   public int getA() {

      return a;

   }

  

  

}

public class Test9 {

   public static void main(String[] args) throws InterruptedException {

      RunnerTest runnerTest = new RunnerTest();

      Thread t = new Thread(runnerTest);

      t.start();

      //t.join();

      t.join(10);

      System.out.println(runnerTest.getA());

   }

}

 

package cn.php.test;

 

class CustomThread1 extends Thread {

 

   public void run() {

      String threadName = Thread.currentThread().getName();

      System.out.println(threadName + " start.");

      try {

        for (int i = 0; i < 5; i++) {

           System.out.println(threadName + " loop at " + i);

           Thread.sleep(1000);

        }

        System.out.println(threadName + " end.");

      } catch (Exception e) {

        System.out.println("Exception from " + threadName + ".run");

      }

   }

}

 

class CustomThread extends Thread {

   CustomThread1 t1;

 

   public CustomThread(CustomThread1 t1) {

      this.t1 = t1;

   }

 

   public void run() {

      String threadName = Thread.currentThread().getName();

      System.out.println(threadName + " start.");

      try {

        t1.join();

        System.out.println(threadName + " end.");

      } catch (Exception e) {

        System.out.println("Exception from " + threadName + ".run");

      }

   }

}

 

public class JoinTestDemo {

 

   public static void main(String[] args) {

      String threadName = Thread.currentThread().getName();

      System.out.println(threadName + " start.");

      CustomThread1 t1 = new CustomThread1();

      CustomThread t = new CustomThread(t1);

      try {

        t1.start();

        Thread.sleep(2000);

        t.start();

        t.join(); // 在代碼2里,將此處注釋掉

      } catch (Exception e) {

        System.out.println("Exception from main");

      }

      System.out.println(threadName + " end!");

   }

}

 

线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。

线程安全类:当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”。

线程的同步和互斥

 

void notifyAll()

解除所有那些在该对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

void notify()

随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在同步方法同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

void wait()

导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

void wait(long millis)和void wait(long millis,int nanos)

导致线程进入等待状态直到它被通知或者经过指定的时间。这些方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部,这是因为:这几个方法要求当前正在运行object.wait()方法的线程拥有object的对象锁。

 

/** 
* Java线程:线程的调度-合并

* @author leizhimin 2009-11-4 9:02:40 
*/ 
publicclass Test {
        publicstaticvoid main(String[] args) {
                Thread t1 = new MyThread1();
                t1.start(); 

                for (int i = 0; i < 20; i++) {
                        System.out.println("主线程第" + i +"次执行!");
                        if (i > 2)try { 
                                //t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
                                t1.join(); 
                        } catch (InterruptedException e) {
                                e.printStackTrace(); 
                        } 
                } 
        } 


class MyThread1 extends Thread { 
        publicvoid run() {
                for (int i = 0; i < 10; i++) {
                        System.out.println("线程1第" + i + "次执行!");
                } 
        } 
}

 

守护线程:守护线程与普通线程写法上基本么啥区别,调用线程对象的方法setDaemon(true),则可以将其设置为守护线程。

守护线程使用的情况较少,但并非无用,举例来说,JVM的垃圾回收、内存管理等线程都是守护线程。还有就是在做数据库应用时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监控连接个数、超时时间、状态等等。

当正在运行的线程都是守护线程时,Java虚拟机退出。

package cn.php.test;

/**

* Java线程:线程的调度-守护线程

*

* @author leizhimin 2009-11-4 9:02:40

*/

public class Test9 {

        public static void main(String[] args) {

                Thread t1 = new MyCommon();

                Thread t2 = new Thread(new MyDaemon());

                t2.setDaemon(true);        //设置为守护线程

 

                t2.start();

                t1.start();

        }

}

 

class MyCommon extends Thread {

        public void run() {

                for (int i = 0; i < 5; i++) {

                        System.out.println("线程1第" + i + "次执行!");

                        try {

                                Thread.sleep(7);

                        } catch (InterruptedException e) {

                                e.printStackTrace();

                        }

                }

        }

}

 

class MyDaemon implements Runnable {

        public void run() {

                for (long i = 0; i < 9999999L; i++) {

                        System.out.println("后台线程第" + i +"次执行!");

                        try {

                                Thread.sleep(7);

                        } catch (InterruptedException e) {

                                e.printStackTrace();

                        }

                }

        }

}

前台线程是保证执行完毕的,后台线程还没有执行完毕就退出了。

void notify()    
                    唤醒在此对象监视器上等待的单个线程。    
void notifyAll()    
                    唤醒在此对象监视器上等待的所有线程。    
void wait()    
                    导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。    
void wait(long timeout)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量。    
void wait(long timeout,int nanos)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

 

  //关闭线程池
 pool.shutdown(); 

可变尺寸的线程池Executors.newCachedThreadPool();

有返回值的线程

可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。

 

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。

新特征-

package cn.php.test;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

 

/**

* Java线程:锁

*

* @author leizhimin 2009-11-5 10:57:29

*/

public class Test {

        public static void main(String[] args) {

                //创建并发访问的账户

                MyCount myCount = new MyCount("95599200901215522", 10000);

                //创建一个锁对象

                Lock lock = new ReentrantLock();  //不区分读写,称这种锁为普通锁

                //创建一个线程池

                ExecutorService pool = Executors.newCachedThreadPool();

                //创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊

                User u1 = new User("张三", myCount, -4000, lock);

                User u2 = new User("张三他爹", myCount, 6000, lock);

                User u3 = new User("张三他弟", myCount, -8000, lock);

                User u4 = new User("张三", myCount, 800, lock);

                //在线程池中执行各个用户的操作

                pool.execute(u1);

                pool.execute(u2);

                pool.execute(u3);

                pool.execute(u4);

                //关闭线程池

                pool.shutdown();

        }

}

 

/**

* 信用卡的用户

*/

class User implements Runnable {

        private String name;                //用户名

        private MyCount myCount;        //所要操作的账户

        private int iocash;                //操作的金额,当然有正负之分了

        private Lock myLock;                //执行操作所需的锁对象

 

        User(String name, MyCount myCount, int iocash, Lock myLock) {

                this.name = name;

                this.myCount = myCount;

                this.iocash = iocash;

                this.myLock = myLock;

        }

 

        public void run() {

                //获取锁

                myLock.lock();

                //执行现金业务

                System.out.println(name + "正在操作" + myCount +"账户,金额为" + iocash +",当前金额为" + myCount.getCash());

                myCount.setCash(myCount.getCash() + iocash);

                System.out.println(name + "操作" + myCount +"账户成功,金额为" + iocash +",当前金额为" + myCount.getCash());

                //释放锁,否则别的线程没有机会执行了

                myLock.unlock();

        }

}

 

/**

* 信用卡账户,可随意透支

*/

class MyCount {

        private String oid;        //账号

        private int cash;            //账户余额

 

        MyCount(String oid, int cash) {

                this.oid = oid;

                this.cash = cash;

        }

 

        public String getOid() {

                return oid;

        }

 

        public void setOid(String oid) {

                this.oid = oid;

        }

 

        public int getCash() {

                return cash;

        }

 

        public void setCash(int cash) {

                this.cash = cash;

        }

 

        @Override

        public String toString() {

                return"MyCount{" +

                                "oid='" + oid + '\'' +

                                ", cash=" + cash +

                                '}';

        }

}

 

为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。

Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;

/** 
* Java线程:新特征-阻塞队列

* @author leizhimin 2009-11-5 14:59:15 
*/ 
publicclass Test {
        publicstaticvoid main(String[] args)throws InterruptedException {
                BlockingQueue bqueue = new ArrayBlockingQueue(20);
                for (int i = 0; i < 30; i++) {
                        //将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。
                        bqueue.put(i); 
                        System.out.println("向阻塞队列中添加了元素:" + i);
                } 
                System.out.println("程序到此运行结束,即将退出----");
        } 
}

 

输出结果:

向阻塞队列中添加了元素:0
向阻塞队列中添加了元素:1 
向阻塞队列中添加了元素:2 
向阻塞队列中添加了元素:3 
向阻塞队列中添加了元素:4 
向阻塞队列中添加了元素:5 
向阻塞队列中添加了元素:6 
向阻塞队列中添加了元素:7 
向阻塞队列中添加了元素:8 
向阻塞队列中添加了元素:9 
向阻塞队列中添加了元素:10 
向阻塞队列中添加了元素:11 
向阻塞队列中添加了元素:12 
向阻塞队列中添加了元素:13 
向阻塞队列中添加了元素:14 
向阻塞队列中添加了元素:15 
向阻塞队列中添加了元素:16 
向阻塞队列中添加了元素:17 
向阻塞队列中添加了元素:18 
向阻塞队列中添加了元素:19

 

可以看出,输出到元素19时候,就一直处于等待状态,因为队列满了,程序阻塞了。

 

这里没有用多线程来演示,没有这个必要。

 

另外,阻塞队列还有更多实现类,用来满足各种复杂的需求:ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue,具体的API差别也很小。

Java线程:新特征-原子量

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicLong;

/** 
* Java线程:新特征-原子量

* @author leizhimin 2009-11-6 9:53:11 
*/ 
publicclass Test {
        publicstaticvoid main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Lock lock = new ReentrantLock(false);
                Runnable t1 = new MyRunnable("张三", 2000,lock);
                Runnable t2 = new MyRunnable("李四", 3600,lock);
                Runnable t3 = new MyRunnable("王五", 2700,lock);
                Runnable t4 = new MyRunnable("老张", 600,lock);
                Runnable t5 = new MyRunnable("老牛", 1300,lock);
                Runnable t6 = new MyRunnable("胖子", 800,lock);
                //执行各个线程
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池
                pool.shutdown(); 
        } 


class MyRunnableimplements Runnable {
        privatestatic AtomicLong aLong =new AtomicLong(10000);        //原子量,每个线程都可以自由操作
        private String name;                //操作人
        privateint x;                            //操作数额
        private Lock lock;

        MyRunnable(String name, int x,Lock lock) {
                this.name = name;
                this.x = x;
                this.lock = lock;
        } 

        publicvoid run() {
                lock.lock(); 
                System.out.println(name + "执行了" + x +",当前余额:" + aLong.addAndGet(x));
                lock.unlock(); 
        } 
}

 

执行结果:

张三执行了2000,当前余额:12000
王五执行了2700,当前余额:14700
老张执行了600,当前余额:15300
老牛执行了1300,当前余额:16600
胖子执行了800,当前余额:17400
李四执行了3600,当前余额:21000

Process finished with exit code 0

 

这里使用了一个对象锁,来控制对并发代码的访问。不管运行多少次,执行次序如何,最终余额均为21000,这个结果是正确的。

 

有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的

主线程等待子线程结束:

package cn.php.test;

 

import java.util.ArrayList;

import java.util.List;

 

public class Test2 {

   public static void main(String[] args) {

      List<Integer> list = new ArrayList<Integer>();

      for (int i = 0; i < 1000; i++) {

        list.add(i);

      }

      List<List<Integer>> splitLists = splitList(list, 400);

      List<SubTask> tlist = new ArrayList<SubTask>();

      for (List<Integer> ls : splitLists) {

        SubTask task = new SubTask(ls);

        tlist.add(task);

         task.start();

      }

      for(SubTask st:tlist){

        try {

           st.join();

        } catch (InterruptedException e) {

           e.printStackTrace();

        }

      }

      System.out.println("主线程结束!");

   }

 

   private static <T> List<List<T>> splitList(List<T> targe, int size) {

      List<List<T>> listArr = new ArrayList<List<T>>();

      // 获取被拆分的数组个数

      int arrSize = targe.size() % size == 0 ? targe.size() / size : targe

           .size() / size + 1;

      for (int i = 0; i < arrSize; i++) {

        List<T> sub = new ArrayList<T>();

        // 把指定索引数据放入到list中

        for (int j = i * size; j <= size * (i + 1) - 1; j++) {

           if (j <= targe.size() - 1) {

              sub.add(targe.get(j));

           }

        }

        listArr.add(sub);

      }

      return listArr;

   }

}

 

class SubTask extends Thread {

 

   List<Integer> l = new ArrayList<Integer>();

 

   public SubTask(List<Integer> list) {

      this.l = list;

   }

 

   @Override

   public void run() {

      for (int i : l) {

        try {

           Thread.sleep(100);

        } catch (InterruptedException e) {

           e.printStackTrace();

        }

        System.out.println(i);

      }

   }

 

}

 

 

 

package cn.php.test;

 

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

 

public class Test2 {

   public static void main(String[] args) {

      List<Integer> list = new ArrayList<Integer>();

      for (int i = 0; i < 1000; i++) {

        list.add(i);

      }

      List<List<Integer>> splitLists = splitList(list, 400);

      List<SubTask> tlist = new ArrayList<SubTask>();

      CountDownLatch count = new CountDownLatch(splitLists.size());

      for (List<Integer> ls : splitLists) {

        SubTask task = new SubTask(ls, count);

        tlist.add(task);

        task.start();

      }

      try {

        count.await();

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

      System.out.println("主线程结束!");

   }

 

   private static <T> List<List<T>> splitList(List<T> targe, int size) {

      List<List<T>> listArr = new ArrayList<List<T>>();

      // 获取被拆分的数组个数

      int arrSize = targe.size() % size == 0 ? targe.size() / size : targe

           .size() / size + 1;

      for (int i = 0; i < arrSize; i++) {

        List<T> sub = new ArrayList<T>();

        // 把指定索引数据放入到list中

        for (int j = i * size; j <= size * (i + 1) - 1; j++) {

           if (j <= targe.size() - 1) {

              sub.add(targe.get(j));

           }

        }

        listArr.add(sub);

      }

      return listArr;

   }

}

 

class SubTask extends Thread {

 

   List<Integer> l = new ArrayList<Integer>();

   CountDownLatch count;

 

   public SubTask(List<Integer> list, CountDownLatch count) {

      this.l = list;

      this.count = count;

   }

 

   @Override

   public void run() {

      for (int i : l) {

        System.out.println(i);

      }

      count.countDown();

   }

 

}

 

 

 

package cn.php.test;

 

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class Test2 {

   public static void main(String[] args) {

      List<Integer> list = new ArrayList<Integer>();

      for (int i = 0; i < 1000; i++) {

        list.add(i);

      }

      List<List<Integer>> splitLists = splitList(list, 400);

      ExecutorService pool = Executors.newFixedThreadPool(5);

      CountDownLatch count = new CountDownLatch(splitLists.size());

      for (List<Integer> ls : splitLists) {

        SubTask task = new SubTask(ls, count);

        pool.execute(task);

      }

      try {

        count.await();

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

      System.out.println("主线程结束!");

   }

 

   private static <T> List<List<T>> splitList(List<T> targe, int size) {

      List<List<T>> listArr = new ArrayList<List<T>>();

      // 获取被拆分的数组个数

      int arrSize = targe.size() % size == 0 ? targe.size() / size : targe

           .size() / size + 1;

      for (int i = 0; i < arrSize; i++) {

        List<T> sub = new ArrayList<T>();

        // 把指定索引数据放入到list中

        for (int j = i * size; j <= size * (i + 1) - 1; j++) {

           if (j <= targe.size() - 1) {

              sub.add(targe.get(j));

           }

        }

        listArr.add(sub);

      }

      return listArr;

   }

}

 

class SubTask extends Thread {

 

   List<Integer> l = new ArrayList<Integer>();

   CountDownLatch count;

 

   public SubTask(List<Integer> list, CountDownLatch count) {

      this.l = list;

      this.count = count;

   }

 

   @Override

   public void run() {

      for (int i : l) {

        try {

           Thread.sleep(100);

        } catch (InterruptedException e) {

           e.printStackTrace();

        }

        System.out.println(i);

      }

      count.countDown();

   }

 

}

 

 

CyclicBarrier使用:

package cn.php.test;

 

import java.io.IOException;

import java.util.Random;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class CyclicBarrierTest {

 

   public static void main(String[] args) throws IOException,

        InterruptedException {

      CyclicBarrier barrier = new CyclicBarrier(3);

 

      ExecutorService executor = Executors.newFixedThreadPool(3);

      executor.submit(new Thread(new Runner(barrier, "1号选手")));

      executor.submit(new Thread(new Runner(barrier, "2号选手")));

      executor.submit(new Thread(new Runner(barrier, "3号选手")));

 

      executor.shutdown();

      System.out.println("=======主线程结束=====");

   }

}

 

class Runner implements Runnable {

   // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)

   private CyclicBarrier barrier;

 

   private String name;

 

   public Runner(CyclicBarrier barrier, String name) {

      super();

      this.barrier = barrier;

      this.name = name;

   }

 

   @Override

   public void run() {

      try {

        Thread.sleep(1000 * (new Random()).nextInt(8));

        System.out.println(name + " 准备好了...");

        // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。

        barrier.await();

      } catch (InterruptedException e) {

        e.printStackTrace();

      } catch (BrokenBarrierException e) {

        e.printStackTrace();

      }

      System.out.println(name + " 起跑!");

   }

}

 

 

posted @ 2015-06-01 14:11  大鹏520  阅读(147)  评论(0编辑  收藏  举报