当前位置: 首页 > news >正文

音乐网站建设论文的立题意义wordpress 移动端 搜索

音乐网站建设论文的立题意义,wordpress 移动端 搜索,贵州凤冈新闻今天,免费ppt下载软件一、线程池 Sun在Java5中#xff0c;对Java线程的类库做了大量的扩展#xff0c;其中线程池就是Java5的新特征之一#xff0c;除了线程池之外#xff0c;还有很多多线程相关的内容#xff0c;为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序#xff0c;… 一、线程池   Sun在Java5中对Java线程的类库做了大量的扩展其中线程池就是Java5的新特征之一除了线程池之外还有很多多线程相关的内容为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序线程部分的新增内容显得尤为重要。     有关Java5线程新特征的内容全部在java.util.concurrent下面里面包含数目众多的接口和类熟悉这部分API特征是一项艰难的学习过程。当然新特征对做多线程程序没有必须的关系在java5之前通用可以写出很优秀的多线程程序。只是代价不一样而已。 线程池的基本思想还是一种对象池的思想开辟一块内存空间里面存放了众多未死亡的线程池中线程执行调度由池管理器来处理。当有线程任务时从池中取一个执行完成后线程对象归池这样可以避免反复创建线程对象所带来的性能开销节省了系统的资源。     在Java5之前要实现一个线程池是相当有难度的现在Java5为我们做好了一切我们只需要按照提供的API来使用即可享受线程池带来的极大便利。 Java5的线程池分好多种固定尺寸的线程池、可变尺寸连接池。   在使用线程池之前必须知道如何去创建一个线程池在Java5中需要了解的是java.util.concurrent.Executors类的API这个类提供大量创建连接池的静态方法是必须掌握的。 a、固定大小的线程池 import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; /** * Java线程线程池- * * */ public class Test { public static void main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool Executors.newFixedThreadPool(2); //创建实现了Runnable接口对象Thread对象当然也实现了Runnable接口 Thread t1 new MyThread(); Thread t2 new MyThread(); Thread t3 new MyThread(); Thread t4 new MyThread(); Thread t5 new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //关闭线程池 pool.shutdown(); } } class MyThread extends Thread{ Override public void run() { System.out.println(Thread.currentThread().getName()正在执行...); } } 运行结果 pool-1-thread-1正在执行... pool-1-thread-1正在执行... pool-1-thread-2正在执行... pool-1-thread-1正在执行... pool-1-thread-2正在执行...  如果将线程池的大小改为4则运行结果如下 pool-1-thread-2正在执行... pool-1-thread-3正在执行... pool-1-thread-3正在执行... pool-1-thread-2正在执行... pool-1-thread-1正在执行...   b、单任务线程池 在上例的基础上改一行创建pool对象的代码为 //创建一个使用单个 worker 线程的 Executor以无界队列方式来运行该线程。 ExecutorService pool Executors.newSingleThreadExecutor(); 则运行结果为 pool-1-thread-1正在执行... pool-1-thread-1正在执行... pool-1-thread-1正在执行... pool-1-thread-1正在执行... pool-1-thread-1正在执行... 对于以上两种连接池大小都是固定的当要加入的池的线程或者任务超过池最大尺寸时候则入此线程池需要排队等待。 一旦池中有线程完毕则排队等待的某个线程会入池执行。  c、可变尺寸的线程池  与上面的类似只是改动下pool的创建方式 //创建一个可根据需要创建新线程的线程池但是在以前构造的线程可用时将重用它们。 ExecutorService pool Executors.newCachedThreadPool(); 运行结果如下 pool-1-thread-1正在执行... pool-1-thread-5正在执行... pool-1-thread-4正在执行... pool-1-thread-3正在执行... pool-1-thread-2正在执行... d、延迟连接池 package concurrent; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit;/** * Java线程线程池- * * */ public class Test { public static void main(String[] args) { //创建一个线程池它可那排在给定延迟后运行命令或者定期地执行ScheduledExecutorService pool Executors.newScheduledThreadPool(2);//创建实现了Runnable接口对象Thread对象当然也实现了Runnable接口 Thread t1 new MyThread(); Thread t2 new MyThread(); Thread t3 new MyThread(); Thread t4 new MyThread(); Thread t5 new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); //使用延迟执行风格的方法pool.schedule(t4, 5, TimeUnit.SECONDS);pool.schedule(t5, 10, TimeUnit.SECONDS);//关闭线程池 pool.shutdown(); } } class MyThread extends Thread{ Override public void run() { System.out.println(Thread.currentThread().getName()正在执行...); } } e、单任务连接线程池 在d的代码基础上做改动 //创建一个单线程执行程序它可安排在给定延迟后运行命令或者定期地执行。 ScheduledExecutorService pool Executors.newSingleThreadScheduledExecutor(); 运行时会发现t4延迟5s后得到执行t5延迟10s后得到执行。运行结果如下 pool-1-thread-2正在执行... pool-1-thread-1正在执行... pool-1-thread-1正在执行... pool-1-thread-2正在执行... pool-1-thread-1正在执行... f、自定义线程池 package concurrent; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Java线程线程池-自定义线程池 * * */ public class Test { public static void main(String[] args) { //创建等待队列 BlockingQueueRunnable bqueue new ArrayBlockingQueueRunnable(20); //创建一个单线程执行程序它可安排在给定延迟后运行命令或者定期地执行。 ThreadPoolExecutor pool new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue); //创建实现了Runnable接口对象Thread对象当然也实现了Runnable接口 Thread t1 new MyThread(); Thread t2 new MyThread(); Thread t3 new MyThread(); Thread t4 new MyThread(); Thread t5 new MyThread(); Thread t6 new MyThread(); Thread t7 new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); pool.execute(t7); //关闭线程池 pool.shutdown(); } } class MyThread extends Thread { Override public void run() { System.out.println(Thread.currentThread().getName() 正在执行...); try { Thread.sleep(100L); } catch (InterruptedException e) { e.printStackTrace(); } } } 运行结构如下创建自定义线程池的构造方法很多本例中参数的含义如下 ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue) 用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。使用 Executors 工厂方法之一比使用此通用构造方法方便得多。  参数corePoolSize - 池中所保存的线程数包括空闲线程。 maximumPoolSize - 池中允许的最大线程数。 keepAliveTime - 当线程数大于核心时此为终止前多余的空闲线程等待新任务的最长时间。 unit - keepAliveTime 参数的时间单位。 workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。 抛出IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于零或者 maximumPoolSize 小于或等于零或者 corePoolSize 大于 maximumPoolSize。 NullPointerException - 如果 workQueue 为 null 自定义连接池稍微麻烦些不过通过创建的ThreadPoolExecutor线程池对象可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。 二、有返回值的线程 在Java5之前线程是没有返回值的常常为了“有”返回值破费周折而且代码很不好写。或者干脆绕过这道坎走别的路了。现在Java终于有可返回值的线程了。  可返回值的任务必须实现Callable接口类似的无返回值的任务必须实现Runnable接口。  执行Callable任务后可以获取一个Future的对象在该对象上调用get就可以获取到Callable任务返回的Object了。  下面是一个简单的例子   package MultiThread; import java.util.concurrent.*; /** * Java线程有返回值的线程 * * */ public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建一个线程池 ExecutorService pool Executors.newFixedThreadPool(2); //创建两个有返回值的任务 CallableString c1 new MyCallable(A); CallableString c2 new MyCallable(B); //执行任务并获取Future对象 FutureString f1 pool.submit(c1); FutureString f2 pool.submit(c2); //从Future对象上获取任务的返回值并输出到控制台 System.out.println(f1.get().toString()); System.out.println(f2.get().toString()); //关闭线程池 pool.shutdown(); } } class MyCallable implements CallableString{ private String oid; MyCallable(String oid) { this.oid oid; } Override public String call() throws Exception { return oid任务返回的内容; } } 运行结果 A任务返回的内容 B任务返回的内容 比较简单要深入了解还需要看Callable和Future接口的API啊。 三、并发库的锁 在Java5中专门提供了锁对象利用锁可以方便的实现资源的封锁用来控制对竞争资源并发访问的控制这些内容主要集中在java.util.concurrent.locks 包下面里面有三个重要的接口Condition、Lock、ReadWriteLock。 接口摘要ConditionCondition 将 Object 监视器方法wait、notify 和 notifyAll分解成截然不同的对象以便通过将这些对象与任意 Lock 实现组合使用为每个对象提供多个等待 setwait-set。LockLock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。ReadWriteLockReadWriteLock 维护了一对相关的锁一个用于只读操作另一个用于写入操作。         有关锁的介绍,API文档解说很多看得很烦还是看个例子再看文档比较容易理解  a、普通锁 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Java线程锁 * * */ public class Test { public static void main(String[] args) { //创建并发访问的账户 MyCount myCount new MyCount(95599200901215522, 10000); //创建一个锁对象 Lock lock new ReentrantLock(); //创建一个线程池 ExecutorService pool Executors.newCachedThreadPool(); //创建一些并发访问用户一个信用卡存的存取的取好热闹啊 UserThread ut1 new UserThread(取款线程1, myCount, -4000, lock); UserThread ut2 new UserThread(存款线程1, myCount, 6000, lock); UserThread ut3 new UserThread(取款线程2, myCount, -8000, lock); UserThread ut4 new UserThread(存款线程2, myCount, 800, lock); //在线程池中执行各个用户的操作 pool.execute(ut1); pool.execute(ut2); pool.execute(ut3); pool.execute(ut4); //关闭线程池 pool.shutdown(); } } /** * 信用卡的用户 线程 * 多个用户线程操作该信用卡 */ class UserThread implements Runnable { private String threadName; //用户线程 private MyCount myCount; //所要操作的账户 private int iocash; //操作的金额当然有正负之分了 private Lock myLock; //执行操作所需的锁对象 UserThread(String name, MyCount myCount, int iocash, Lock myLock) { this.threadName name; this.myCount myCount; this.iocash iocash; this.myLock myLock; } public void run() { //获取锁 myLock.lock(); //执行现金业务 System.out.println(threadName 正在操作 myCount 账户操作金额为 iocash 当前金额为 myCount.getCash()); myCount.setCash(myCount.getCash() iocash); System.out.println(\t操作成功操作金额为 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 }; } } 运行结果 取款线程1正在操作MyCount{oid95599200901215522, cash10000}账户操作金额为-4000当前金额为10000操作成功操作金额为-4000当前金额为6000 存款线程1正在操作MyCount{oid95599200901215522, cash6000}账户操作金额为6000当前金额为6000操作成功操作金额为6000当前金额为12000 存款线程2正在操作MyCount{oid95599200901215522, cash12000}账户操作金额为800当前金额为12000操作成功操作金额为800当前金额为12800 取款线程2正在操作MyCount{oid95599200901215522, cash12800}账户操作金额为-8000当前金额为12800操作成功操作金额为-8000当前金额为4800 从上面的输出可以看到利用锁对象太方便了比直接在某个不知情的对象上用锁清晰多了。但一定要注意的是在获取了锁对象后用完后应该尽快释放锁以便别的等待该锁的线程有机会去执行。 b、读写锁  在a中提到了Lock接口以及对象使用它可以很优雅的控制了竞争资源的安全访问但是这种锁不区分读写称这种锁为普通锁。为了提高性能Java提供了读写锁在读的地方使用读锁在写的地方使用写锁灵活控制在一定程度上提高了程序的执行效率。 Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock也有具体的实现ReentrantReadWriteLock详细的API可以查看JavaAPI文档。 下面这个例子是在文例子的基础上将普通锁改为读写锁并添加账户余额查询的功能代码如下 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock;/** * Java线程锁 * * */ public class Test { public static void main(String[] args) { //创建并发访问的账户 MyCount myCount new MyCount(95599200901215522, 10000); //创建一个锁对象 ReadWriteLock lock new ReentrantReadWriteLock(); //创建一个线程池 ExecutorService pool Executors.newCachedThreadPool(); //创建一些并发访问用户线程一个信用卡存的存取的取好热闹啊 UserThread ut1 new UserThread(取款线程1, myCount, -4000, lock,false); UserThread ut2 new UserThread(存款线程1, myCount, 6000, lock,false); UserThread ut3 new UserThread(取款线程2, myCount, -8000, lock,false); UserThread ut4 new UserThread(存款线程2, myCount, 800, lock,false); UserThread ut5 new UserThread(查询, myCount, 0, lock,true);//在线程池中执行各个用户的操作 pool.execute(ut1); pool.execute(ut2); pool.execute(ut3); pool.execute(ut4); pool.execute(ut5);//关闭线程池 pool.shutdown(); } } /** * 信用卡的用户 线程 * 多个用户线程操作该信用卡 */ class UserThread implements Runnable { private String threadName; //用户线程 private MyCount myCount; //所要操作的账户 private int iocash; //操作的金额当然有正负之分了 private ReadWriteLock myLock; //执行操作所需的锁对象 private boolean ischeck; //是否查询 UserThread(String name, MyCount myCount, int iocash, ReadWriteLock myLock,boolean ischeck) { this.threadName name; this.myCount myCount; this.iocash iocash; this.myLock myLock; this.ischeckischeck;} public void run() {if(ischeck){//获取读锁 myLock.readLock().lock(); //执行查询System.out.println(读threadName 正在查询 myCount 账户当前金额为 myCount.getCash()); //释放获取到的读锁myLock.readLock().unlock();}else{//获取写锁myLock.writeLock().lock();myCount.setCash(myCount.getCash() iocash); System.out.println(写threadName操作成功操作金额为 iocash 当前金额为 myCount.getCash()); //释放锁获取到的写锁myLock.writeLock().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 }; } }  运行结果 写取款线程1操作成功操作金额为-4000当前金额为6000 写取款线程2操作成功操作金额为-8000当前金额为-2000 写存款线程1操作成功操作金额为6000当前金额为4000 读查询正在查询MyCount{oid95599200901215522, cash4000}账户当前金额为4000 写存款线程2操作成功操作金额为800当前金额为4800 在实际开发中最好在能用读写锁的情况下使用读写锁而不要用普通锁以求更好的性能。  四、信号量 Java的信号量实际上是一个功能完毕的计数器对控制一定资源的消费与回收有着很重要的意义信号量常常用于多线程的代码中并能监控有多少数目的线程等待获取资源并且通过信号量可以得知可用资源的数目等等这里总是在强调“数目”二字但不能指出来有哪些在等待哪些资源可用。  因此本人认为这个信号量类如果能返回数目还能知道哪些对象在等待哪些资源可使用就非常完美了仅仅拿到这些概括性的数字对精确控制意义不是很大。目前还没想到更好的用法。 下面是一个简单的例子 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * Java线程信号量 * * */ public class Test { public static void main(String[] args) { MyPool myPool new MyPool(20); //创建线程池 ExecutorService threadPool Executors.newFixedThreadPool(2); MyThread t1 new MyThread(任务A, myPool, 3); MyThread t2 new MyThread(任务B, myPool, 12); MyThread t3 new MyThread(任务C, myPool, 7); //在线程池中执行任务 threadPool.execute(t1); threadPool.execute(t2); threadPool.execute(t3); //关闭池 threadPool.shutdown(); } } /** * 一个池 */ class MyPool { private Semaphore sp; //池相关的信号量 /** * 池的大小这个大小会传递给信号量 * * param size 池的大小 */ MyPool(int size) { this.sp new Semaphore(size); } public Semaphore getSp() { return sp; } public void setSp(Semaphore sp) { this.sp sp; } } class MyThread extends Thread { private String threadName; //线程的名称 private MyPool pool; //自定义池 private int x; //申请信号量的大小 MyThread(String threadName, MyPool pool, int x) { this.threadName threadName; this.pool pool; this.x x; } public void run() { try { //从此信号量获取给定数目的许可 pool.getSp().acquire(x); //todo也许这里可以做更复杂的业务 System.out.println(threadName 成功获取了 x 个许可); } catch (InterruptedException e) { e.printStackTrace(); } finally { //释放给定数目的许可将其返回到信号量。 pool.getSp().release(x); System.out.println(threadName 释放了 x 个许可); } } } 运行结果 任务A成功获取了3个许可 任务B成功获取了12个许可 任务B释放了12个许可 任务C成功获取了7个许可 任务A释放了3个许可 任务C释放了7个许可 从结果可以看出信号量仅仅是对池资源进行监控但不保证线程的安全因此在使用时候应该自己控制线程的安全访问池资源。 五、阻塞队列     阻塞队列是Java5线程新特征中的内容Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue阻塞队列的概念是一个指定长度的队列如果队列满了添加新元素的操作会被阻塞等待直到有空位为止。同样当队列为空时候请求队列元素的操作同样会阻塞等待直到有可用元素为止。 有了这样的功能就为多线程的排队等候的模型实现开辟了便捷通道非常有用。 java.util.concurrent.BlockingQueue继承了java.util.Queue接口可以参看API文档。 下面给出一个简单应用的例子 package MultiThread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ArrayBlockingQueue; /** * Java线程并发库-阻塞队列 * * */ public class Test { public static void main(String[] args) throws InterruptedException { BlockingQueueInteger bqueue new ArrayBlockingQueueInteger(20); for (int i 0; i 30; i) { //将指定元素添加到此队列中如果没有可用空间将一直等待如果有必要。 bqueue.put(i); System.out.println(向阻塞队列中添加了元素: i); } System.out.println(程序到此运行结束即将退出----); } } 运行结果 由于阻塞队列的大小为20个当超过这个数目又没有元素出队列的时候队列将会阻塞。到后来的某一个时刻程序将阻塞队列中的元素出队列后面的元素才可以进队列。 六、阻塞栈 对于阻塞栈与阻塞队列相似。不同点在于栈是“后入先出”的结构每次操作的是栈顶而队列是“先进先出”的结构每次操作的是队列头。 这里要特别说明一点的是阻塞栈是Java6的新特征。、 Java为阻塞栈定义了接口java.util.concurrent.BlockingDeque其实现类也比较多具体可以查看JavaAPI文档。 下面看一个简单例子 package MultiThread;import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; class HelloWorldThread {/** * Java线程并发库-阻塞栈* * */ public static void main(String[] args) {BlockingDequeInteger bstacknew LinkedBlockingDequeInteger(20) ;for(int i0;i30;i){//将指定元素添加到阻塞栈中如果没有可用空间将一直等待如果有必要。 bstack.push(i);System.out.println(向阻塞栈中添加了元素: i); if(bstack.size()20){System.out.println(队列满弹出bstack.pop()); System.out.println(队列满弹出bstack.pop()); System.out.println(队列满弹出bstack.pop()); }}System.out.println(程序到此运行结束即将退出----); }} 程序的运行结果和阻塞队列的运行结果一样程序并没结束二是阻塞住了原因是栈已经满了后面追加元素的操作都被阻塞了。 七、条件变量     条件变量是Java5线程中很重要的一个概念顾名思义条件变量就是表示条件的一种变量。但是必须说明这里的条件是没有实际含义的仅仅是个标记而已并且条件的含义往往通过代码来赋予其含义。这里的条件和普通意义上的条件表达式有着天壤之别。条件变量都实现了java.util.concurrent.locks.Condition接口条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的这样条件就和一个锁对象绑定起来了。因此Java中的条件变量只能和锁配合使用来控制并发程序访问竞争资源的安全。     条件变量的出现是为了更精细控制线程等待与唤醒在Java5之前线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法这样的处理不够精细。而在Java5中一个锁可以有多个条件每个条件上可以有多个线程等待通过调用await()方法可以让线程在该条件下等待。当调用signalAll()方法又可以唤醒该条件下的等待的线程。有关Condition接口的API可以具体参考JavaAPI文档。 条件变量比较抽象原因是他不是自然语言中的条件概念而是程序控制的一种手段。       下面以一个银行存取款的模拟程序为例来揭盖Java多线程条件变量的神秘面纱 有一个账户多个用户线程在同时操作这个账户有的存款有的取款存款随便存取款有限制不能透支任何试图透支的操作都将等待里面有足够存款才执行操作。 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; 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); //创建一个线程池 ExecutorService pool Executors.newFixedThreadPool(2); Thread t1 new SaveThread(张三, myCount, 2000); Thread t2 new SaveThread(李四, myCount, 3600); Thread t3 new DrawThread(王五, myCount, 2700); Thread t4 new SaveThread(老张, myCount, 600); Thread t5 new DrawThread(老牛, myCount, 1300); Thread t6 new DrawThread(胖子, myCount, 800); //执行各个线程 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); //关闭线程池 pool.shutdown(); } } /** * 存款线程类 */ class SaveThread extends Thread { private String name; //操作人 private MyCount myCount; //账户 private int x; //存款金额 SaveThread(String name, MyCount myCount, int x) { this.name name; this.myCount myCount; this.x x; } public void run() { myCount.saving(x, name); } } /** * 取款线程类 */ class DrawThread extends Thread { private String name; //操作人 private MyCount myCount; //账户 private int x; //存款金额 DrawThread(String name, MyCount myCount, int x) { this.name name; this.myCount myCount; this.x x; } public void run() { myCount.drawing(x, name); } } /** * 普通银行账户不可透支 */ class MyCount { private String oid; //账号 private int cash; //账户余额 private Lock lock new ReentrantLock(); //账户锁 private Condition _save lock.newCondition(); //存款条件 private Condition _draw lock.newCondition(); //取款条件 MyCount(String oid, int cash) { this.oid oid; this.cash cash; } /** * 存款 * * param x 操作金额 * param name 操作人 */ public void saving(int x, String name) { lock.lock(); //获取锁 if (x 0) { cash x; //存款 System.out.println(name 存款 x 当前余额为 cash); } _draw.signalAll(); //唤醒所有取款等待线程lock.unlock(); //释放锁 } /** * 取款 * * param x 操作金额 * param name 操作人 */ public void drawing(int x, String name) { lock.lock(); //获取锁 try { if (cash - x 0) { _draw.await(); //阻塞取款操作 } else { cash - x; //取款 System.out.println(name 取款 x 当前余额为 cash); } _save.signalAll(); //唤醒所有存款操作线程 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); //释放锁 } } } 当然除了使用并发库来实现存取款操作我们也可以使用synchronized的方法、synchronized的代码块来实现。对比并发库、synchronized方法、synchronized代码块第一种最灵活第二种代码最简单第三种容易犯错。 八、原子量      所谓的原子量即操作变量的操作是“原子的”该操作不可再分因此是线程安全的。为何要使用原子变量呢原因是多个线程对单个变量操作也会引起一些问题。在Java5之前可以通过volatile、synchronized关键字来解决并发访问的安全问题但这样太麻烦。Java5之后专门提供了用来进行单变量多线程并发安全访问的工具包java.util.concurrent.atomic其中的类也很简单。 下面给出一个反面例子切勿模仿 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; /** * Java线程新特征-原子量 * * */ public class Test { public static void main(String[] args) { ExecutorService pool Executors.newFixedThreadPool(2); Runnable t1 new MyRunnable(张三, 2000); Runnable t2 new MyRunnable(李四, 3600); Runnable t3 new MyRunnable(王五, 2700); Runnable t4 new MyRunnable(老张, 600); Runnable t5 new MyRunnable(老牛, 1300); Runnable t6 new MyRunnable(胖子, 800); //执行各个线程 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); //关闭线程池 pool.shutdown(); } } class MyRunnable implements Runnable { private static AtomicLong aLong new AtomicLong(10000); //原子量每个线程都可以自由操作 private String name; //操作人 private int x; //操作数额 MyRunnable(String name, int x) { this.name name; this.x x; } public void run() { System.out.println(name 执行了 x 当前余额 aLong.addAndGet(x)); } } 运行结果一 李四执行了3600当前余额13600 张三执行了2000当前余额15600 老张执行了600当前余额18900 老牛执行了1300当前余额20200 胖子执行了800当前余额21000 王五执行了2700当前余额18300 运行结果二 张三执行了2000当前余额12000 王五执行了2700当前余额14700 老张执行了600当前余额15300 老牛执行了1300当前余额16600 胖子执行了800当前余额17400 李四执行了3600当前余额21000 运行结果三 张三执行了2000当前余额12000 王五执行了2700当前余额18300 老张执行了600当前余额18900 老牛执行了1300当前余额20200 胖子执行了800当前余额21000 李四执行了3600当前余额15600 从运行结果可以看出虽然使用了原子量但是程序并发访问还是有问题那究竟问题出在哪里了 这里要注意的一点是原子量虽然可以保证单个变量在某一个操作过程的安全但无法保证你整个代码块或者整个程序的安全性。因此通常还应该使用锁等同步机制来控制整个程序的安全性。 下面是对上述代码的修正 package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;/** * Java线程并发库-原子量 * * */ public class Test { public static void main(String[] args) { ExecutorService pool Executors.newFixedThreadPool(2); Lock locknew ReentrantLock();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 MyRunnable implements Runnable { private static AtomicLong aLong new AtomicLong(10000); //原子量每个线程都可以自由操作 private String name; //操作人 private int x; //操作数额 private Lock lock;MyRunnable(String name, int x,Lock lock) { this.name name; this.x x; this.locklock;} public void run() { lock.lock();System.out.println(name 执行了 x 当前余额 aLong.addAndGet(x)); lock.unlock();} } 运行结果 张三执行了2000当前余额12000 李四执行了3600当前余额15600 王五执行了2700当前余额18300 老张执行了600当前余额18900 老牛执行了1300当前余额20200 胖子执行了800当前余额21000 这里使用了一个对象锁来控制对并发代码的访问。不管运行多少次执行次序如何最终余额均为21000这个结果是正确的。 有关原子量的用法很简单关键是对原子量的认识原子仅仅是保证变量操作的原子性但整个程序还需要考虑线程安全的。 九、障碍器      Java5中添加了障碍器类为了适应一种新的设计需求比如一个大型的任务常常需要分配好多子任务去执行只有当所有子任务都执行完成时候才能执行主任务这时候就可以选择障碍器了。障碍器是多线程并发控制的一种手段用法很简单。 下面给个例子 package MultiThread; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * Java线程新特征-障碍器 * * */ public class Test { public static void main(String[] args) { //创建障碍器并设置MainTask为所有定数量的线程都达到障碍点时候所要执行的任务(Runnable) CyclicBarrier cb new CyclicBarrier(7, new MainTask()); new SubTask(A, cb).start(); new SubTask(B, cb).start(); new SubTask(C, cb).start(); new SubTask(D, cb).start(); new SubTask(E, cb).start(); new SubTask(F, cb).start(); new SubTask(G, cb).start(); } } /** * 主任务 */ class MainTask implements Runnable { public void run() { System.out.println(主任务执行了); } } /** * 子任务 */ class SubTask extends Thread { private String name; private CyclicBarrier cb; SubTask(String name, CyclicBarrier cb) { this.name name; this.cb cb; } public void run() { System.out.println([子任务 name ]开始执行了); for (int i 0; i 999999; i) ; //模拟耗时的任务 System.out.println([子任务 name ]开始执行完成了并通知障碍器已经完成); try { //通知障碍器已经完成让出锁并使得跳跃的障碍数目-1cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } 运行结果 [子任务B]开始执行了 [子任务E]开始执行了 [子任务C]开始执行了 [子任务D]开始执行了 [子任务A]开始执行了 [子任务E]开始执行完成了并通知障碍器已经完成 [子任务B]开始执行完成了并通知障碍器已经完成 [子任务A]开始执行完成了并通知障碍器已经完成 [子任务C]开始执行完成了并通知障碍器已经完成 [子任务D]开始执行完成了并通知障碍器已经完成 [子任务F]开始执行了 [子任务F]开始执行完成了并通知障碍器已经完成 [子任务G]开始执行了 [子任务G]开始执行完成了并通知障碍器已经完成 主任务执行了 从执行结果可以看出所有子任务完成的时候主任务执行了达到了控制的目标 总结 Java线程是Java语言中一个非常重要的部分Java5之前多线程的语言支持还是比较弱的内容也较少写一个复杂的多线程程序是相当有挑战性的。 在Java5以后Java对多线程做了很多扩展扩展部分称之为并发包。这部分内容大大增强了Java多线程编程的能力通过使用Java5线程新特征的API可以很容易的做出复杂的多线程程序。与其他语言相比已经是相当强悍了。 转载于:https://www.cnblogs.com/shudonghe/p/3318494.html
http://wiki.neutronadmin.com/news/132322/

相关文章:

  • wordpress网站的彻底清理重庆seo整站优化服务
  • 网站右侧虚代码网站建设招标
  • 免费自己建网站网站运营无经验可以做吗
  • 网站建设项目需求分析报告怎么免费做文学网站
  • 沈阳网站维护公司桂林旅游
  • 网站首页设计费用网站被墙查询
  • 做盗版小说网站违法吗软文代写费用
  • 健康网站可以做推广吗饭店装修设计
  • 模板网站可以做推广吗手机端做的优秀的网站
  • 国内专业网站建设公司茂名公司制作网站
  • 政协网站建设意义吴桥县网站建设
  • 电子商务网站建设是学什么软件网站支付方案的设计
  • 自己建设小城市网站得多少钱google搜索排名优化
  • 模拟炒股网站开发服务商标有哪些
  • 呼市做网站公司濮阳建设网
  • 北京做环评备案的网站百度seo排名优化提高流量
  • 珠海做网站三年多少钱外贸公司网站建设 重点是什么
  • 前端角度实现网站首页加载慢优化永久免费无代码开发平台
  • 外贸推广网站有哪些公司简介宣传册设计样本图片
  • 住房与城乡建设部网站注册中心网站开发是培训
  • 网站建设与运营市场开发方案网站内容建设的建议
  • 广州网站建设公技术支持 祥云平台 英文网站
  • 男生为女生做网站全网vip影视网站一键搭建
  • 网站上线 模板做网站都有哪些费用
  • 使用他人api做网站wordpress侧边栏加视频板块
  • 5 网站建设的基本步骤是做超链接的网站
  • 教育类手机网站模板下载邢台吧贴吧
  • 深圳市作网站的公司汉中网站建设公司推荐
  • 做养生网站需要证件吗如何免费做网页
  • 建设银行网站 查余额查询网站上传视频教程