??xml version="1.0" encoding="utf-8" standalone="yes"?>激情福利在线,日韩一级完整毛片,日韩精品无码一区二区三区 http://www.aygfsteel.com/stevenjohn/category/51101.html那些青春的岁?/description>zh-cn Sun, 28 Apr 2013 16:06:50 GMT Sun, 28 Apr 2013 16:06:50 GMT 60 CyclicBarrier与CountDownLatch、栅栏与计数?/title> http://www.aygfsteel.com/stevenjohn/archive/2013/04/28/398548.htmlabin abin Sun, 28 Apr 2013 07:37:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/04/28/398548.html http://www.aygfsteel.com/stevenjohn/comments/398548.html http://www.aygfsteel.com/stevenjohn/archive/2013/04/28/398548.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/398548.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/398548.html
我想应该有很多办法,如果是简单的1Q?关系Q那么可以waitQ)和notifyQ)解决Q就像一把锁和一把钥匙;如果?QN关系Q这?需要关心N的所有状态了Q最W的办法?可以L看N当前的状态,轮询询问工作是否做完。而好点的办法是N做完后主动告?Q?span style="color: #0000ff">然后N׃?U选择Q要么听?的命令,要么l箋q自己其他的zR?/span>
用传l的Ҏ我想应该是都能实现的Q而JDK1.5提供了CyclicBarrier与CountDownLatch来解决了q两个问题,而她们的区别是:
CyclicBarrier使所有线E相互等待,而CountDownLatch使一个或多个U程{待其他U程。区别类g面蓝色字体,CountDownLatch不会{待其他U程了,只要做完自己的工作就q自qzd了,也就是run()Ҏ里其他的d?/p>
ExampleQ?/p>
public static void testCountDownLatch() throws InterruptedException { CountDownLatch cdl = new CountDownLatch( 2 ); ExecutorService exe = Executors.newFixedThreadPool( 2 ); class Bow implements Runnable { CountDownLatch cdl; public Bow(CountDownLatch cdl) { this .cdl = cdl; } public void run() { System.out.println( " The bow is coming " ); System.out.println( " kick a bow " ); this .cdl.countDown(); System.out.println( " do other thing " ); } } exe.execute( new Bow(cdl)); exe.execute( new Bow(cdl)); exe.shutdown(); System.out.println( " Wait " ); cdl.await(); System.out.println( " End.. " ); } public static void main(String[] args) { try { Test.testCountDownLatch(); } catch (InterruptedException e) { } }
输出的结果ؓQ?/p>
The bow is coming kick a bow do other thing Wait... The bow is coming kick a bow do other thing End..
如上所说do other thing不受影响?/p>
写了一个CyclicBarrier的例子:
public static void testCyclicBarrier() throws InterruptedException, BrokenBarrierException { CyclicBarrier barr = new CyclicBarrier( 2 + 1 ); ExecutorService exe = Executors.newFixedThreadPool( 2 ); class Bow implements Runnable { CyclicBarrier barr; public Bow(CyclicBarrier barr) { this .barr = barr; } public void run() { System.out.println( " The bow is coming " ); System.out.println( " kick a down " ); try { barr.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(" do other thing " ); } } exe.execute(new Bow(barr)); exe.execute( new Bow(barr)); exe.shutdown(); System.out.println( " Wait " ); barr.await(); System.out.println( " End.. " ); } public static void main(String[] args) { try { Test.testCyclicBarrier(); } catch (InterruptedException e) { } catch (BrokenBarrierException e) { } }
输出l果为:
Wait... The bow is coming kick a down The bow is coming kick a downdo other thing End..do other thing
ȝQ?/span>
我们看到do other thing被阻塞了Q直到最后才执行Q可见,栅栏和计数器的目完全不同了。向Doug Lea牛h学习Q)
在网上看到很多h对于CountDownLatch和CyclicBarrier的区别简单理解ؓCountDownLatch是一ơ性的Q而CyclicBarrier在调用reset之后q可以l用。那如果只是q么单的话,我觉得CyclicBarrier单命名ؓResetableCountDownLatch 好了Q显然不是的?br />我的理解是,要从他们的设计目的去看这两个cRjavadoc里面的描q是q样的?
CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
可能是我的英语不够好吧, 我感觉从q个javadoc里面要准理解他们的差异q是不容易的?br />我的理解?/p>
CountDownLatch : 一个线E?/strong>(或者多?Q?{待另外N个线E?/strong>完成某个事情 之后才能执行? CyclicBarrier : N个线E?/strong>怺{待QQ何一个线E完成之前,所有的U程都必ȝ待?br />q样应该清楚一点了Q对于CountDownLatch来说Q重Ҏ那个“一个线E?#8221; , 是它在等待, 而另外那N的线E在?strong>“某个事情” 做完之后可以l箋{待Q可以终止。而对于CyclicBarrier来说Q重Ҏ?strong>N个线E?/strong>Q他们之间Q何一个没有完成,所有的U程都必ȝ待?/p>
CountDownLatch 是计数器, U程完成一个就C? 像 报数一? 只不q是递减? 而CyclicBarrier更像一个水? U程执行想水流, 在水闸处都会堵住, {到水满(U程到齐)? 才开始泄?
]]>Object之wait,notify,notifyAll http://www.aygfsteel.com/stevenjohn/archive/2013/01/16/394330.htmlabin abin Wed, 16 Jan 2013 15:46:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/01/16/394330.html http://www.aygfsteel.com/stevenjohn/comments/394330.html http://www.aygfsteel.com/stevenjohn/archive/2013/01/16/394330.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/394330.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/394330.html 在这里我们首先学习一下公共方法wait,notify,notifyAll?/p>
waitҎ可以使在当前U程的对象等待,直到别的U程调用此对象的notify或notifyAllҎQ注意:调用的是此对象的notify和notifyAllQ,q且当前q行的线E必d有此对象的对象监视器
package com.abin.lee.thread.thread;
public class CarryTask extends Thread { public void run() { try { synchronized (this) { Thread t = Thread.currentThread(); System.out.println(t.getId() + t.getName() + ":task start, wait for notify..."); this.wait(); System.out.println(t.getId() + t.getName() + ":task continue..."); } } catch (InterruptedException ex) { System.out.println(CarryTask.class.getName()); } }
}
package com.abin.lee.thread.thread;
public class CarryWait { public static void main(String[] args) throws InterruptedException { CarryTask task = new CarryTask(); Thread t = Thread.currentThread(); System.out.println(t.getId() + t.getName() + ":task start..."); task.start(); Thread.sleep(2000); synchronized (task) { System.out.println("id="+Thread.currentThread().getId()+",Name="+Thread.currentThread().getName()+",task="+task+",notify"); task.notify(); } }
}
http://www.iteye.com/topic/1124814 ]]> Future FutureTask http://www.aygfsteel.com/stevenjohn/archive/2013/01/10/394071.htmlabin abin Thu, 10 Jan 2013 06:17:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/01/10/394071.html http://www.aygfsteel.com/stevenjohn/comments/394071.html http://www.aygfsteel.com/stevenjohn/archive/2013/01/10/394071.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/394071.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/394071.html //实例一Q这里面用到了信号量Semaphore和FutureTask
package net.abin.lee.mythread.callable;
import java.util.concurrent.Callable; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock;
public class FutureGo implements Callable<String> { private String message; private static final Semaphore semaphore=new Semaphore(3); private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock(); public FutureGo(String message) { this.message = message; }
public String call() throws InterruptedException { semaphore.acquire(); Lock read=rwl.readLock(); Lock write=rwl.readLock(); read.lock(); System.out.println("message"+message+",Name"+Thread.currentThread().getName()+"q来?); read.unlock(); write.lock(); String result=message+"你好!"; Thread.sleep(1000); System.out.println("message"+message+"Name"+Thread.currentThread().getName()+"d?); write.unlock(); semaphore.release(); return result; } } //FutureTaskTest.java
package net.abin.lee.mythread.callable;
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask;
public class FutureTaskTest { public static void main(String[] args) throws InterruptedException, ExecutionException { Callable<String> go = new FutureGo("abin"); FutureTask<String> task = new FutureTask<String>(go); ExecutorService executor = Executors.newCachedThreadPool(); if (!executor.isShutdown()) { executor.execute(task); } String result = ""; if (!task.isDone()) { result = (String) task.get(); System.out.println("result=" + result); } executor.shutdown(); }
}
//实例一Q这里面用到了信号量Semaphore和FutureTask
]]> javaU程q发库学?-CyclicBarrier http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393933.htmlabin abin Mon, 07 Jan 2013 16:39:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393933.html http://www.aygfsteel.com/stevenjohn/comments/393933.html http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393933.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/393933.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/393933.html
public class CyclicBarrier
extends Object
一个同步辅助类Q它允许一l线E互相等待,直到到达某个公共屏障?nbsp;(common barrier point)。在涉及一l固定大的U程的程序中Q这些线E必M时地互相{待Q此?nbsp;CyclicBarrier 很有用。因 barrier 在释攄待线E后可以重用Q所以称它ؓ循环 ?nbsp;barrier?br />CyclicBarrier 支持一个可选的 Runnable 命oQ在一l线E中的最后一个线E到达之后(但在释放所有线E之前)Q该命o只在每个屏障点运行一ơ。若在l所有参与线E之前更新共享状态,此屏障操?nbsp;很有用?br />以上是jdk文档的说?br />
* 现在说说我们今天zd的内宏V首先我们要在公司大厅集合、然后参观陈云故?br /> * 参观完后集合、准备去淀水湖参观。(?辆R、对?个线E)
*
* 我们必须{大安到齐了才能去下个地方、比如说 、在公司集合?辆R子都C才能出发
* 要不然h装不下啊。这是我们可以用到javaU程q发库的CyclicBarrierc?br />
public class CyclicBarrierTest {
public static void main(String[] args) {
final CyclicBarrier cb = new CyclicBarrier(3);
//final Semaphore semaphore=new Semaphore(1);
for (int i = 1; i <= 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//semaphore.acquire();
System.out.println(Thread.currentThread().getName()
+ "公司大厅集合");
System.out.println(Thread.currentThread().getName()
+ "公司大厅{待....");
//semaphore.release();
cb.await();
Thread.sleep(2000);
//semaphore.acquire();
System.out.println(Thread.currentThread().getName()
+ "陈云故居集合");
System.out.println(Thread.currentThread().getName()
+ "陈云故居{待....");
//semaphore.release();
cb.await();
Thread.sleep(2000);
//semaphore.acquire();
System.out.println(Thread.currentThread().getName()
+ "淀水湖集合");
System.out.println(Thread.currentThread().getName()
+ "淀水湖{待....准备回家?);
//semaphore.release();
cb.await();
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
以下是输出结果:
Thread-0公司大厅集合
Thread-0公司大厅{待....
Thread-2公司大厅集合
Thread-1公司大厅集合
Thread-1公司大厅{待....
Thread-2公司大厅{待....
Thread-0陈云故居集合
Thread-1陈云故居集合
Thread-2陈云故居集合
Thread-1陈云故居{待....
Thread-0陈云故居{待....
Thread-2陈云故居{待....
Thread-0淀水湖集合
Thread-2淀水湖集合
Thread-1淀水湖集合
Thread-2淀水湖{待....准备回家?br />Thread-0淀水湖{待....准备回家?br />Thread-1淀水湖{待....准备回家?br />
***注意上述代码中的SemaphorecR它也是javaU程q发库中的一个类、更多具体作用我们以后再探讨?br />以下是用Semaphore后的输出l果Q(怿你已l知道不同的地方了)
Thread-0公司大厅集合
Thread-0公司大厅{待....
Thread-1公司大厅集合
Thread-1公司大厅{待....
Thread-2公司大厅集合
Thread-2公司大厅{待....
Thread-2陈云故居集合
Thread-2陈云故居{待....
Thread-1陈云故居集合
Thread-1陈云故居{待....
Thread-0陈云故居集合
Thread-0陈云故居{待....
Thread-2淀水湖集合
Thread-2淀水湖{待....准备回家?br />Thread-1淀水湖集合
Thread-1淀水湖{待....准备回家?br />Thread-0淀水湖集合
Thread-0淀水湖{待....准备回家?br />
http://blog.sina.com.cn/s/blog_7f448c520101219g.html ]]> javaU程q发库学?-Exchanger http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393932.htmlabin abin Mon, 07 Jan 2013 16:35:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393932.html http://www.aygfsteel.com/stevenjohn/comments/393932.html http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393932.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/393932.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/393932.html
public class Exchanger<V>
extends Object
可以在对中对元素q行配对和交换的U程的同步点。每个线E将条目上的某个Ҏ呈现l?nbsp;exchange ҎQ与伙伴U程q行匚wQƈ且在q回时接收其伙伴的对象。Exchanger 可能被视?nbsp;SynchronousQueue 的双向Ş式。Exchanger 可能在应用程序(比如遗传法和管道设计)中很有用?br />
以上是jdk文档的说明?br />
* 今天公司党委l织zd?2点半call我电话、我?0码的速度狂奔q去、上了一个R子(A车)?br /> * 戴着眼镜四处瞄了下,没发C么美奛_。假寐了一会儿Q司另外一个R子(B车)上要换过?br /> * 一个h、让车子上的ZM个去B车。由于地势原因、我׃M?br /> *
* 一路上H然惛_了javaU程q发库中的ExchangercRA车我们可以看作是一个线E、B车我们也可以
* 看作是一个线E,我和B车上的一位美x位子Q就可以用到ExchangercȝexchangeҎ?br /> *
* 代码如下Q?br />
public class ExchangerTest {
public static void main(String[] args) {
final Exchanger<String> exchange=new Exchanger<String>();
//final String a="yupan";
//final String b="a girl";
final String[] carA=new String[]{"zhangsan","lisi","yupan"};
final String[] carB=new String[]{"meinv_a","meinv_b","meinv_c"};
//A车线E?br /> new Thread(new Runnable(){
String[] carA_copy=carA;
@Override
public void run() {
try {
System.out.println("交换前:A车上的第三位乘客Q?+carA[2]);
carA_copy[2]=exchange.exchange(carA_copy[2]);
System.out.println("交换后:A车上的第三位乘客Q?+carA[2]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//B车线E?br /> new Thread(new Runnable(){
String[] carB_copy=carB;
@Override
public void run() {
try {
System.out.println("交换前:B车上的第三位乘客Q?+carB[2]);
carB_copy[2]=exchange.exchange(carB_copy[2]);
System.out.println("交换后:B车上的第三位乘客Q?+carB[2]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
输出l果Q?br />
交换前:A车上的第三位乘客Qyupan
交换前:B车上的第三位乘客Qmeinv_c
交换后:B车上的第三位乘客Qyupan
交换后:A车上的第三位乘客Qmeinv_c
http://blog.sina.com.cn/s/blog_7f448c5201012183.html ]]> Java 信号?Semaphore 介绍 http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393930.htmlabin abin Mon, 07 Jan 2013 16:11:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393930.html http://www.aygfsteel.com/stevenjohn/comments/393930.html http://www.aygfsteel.com/stevenjohn/archive/2013/01/08/393930.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/393930.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/393930.html Semaphore 当前在多U程环境下被扩放使用Q?/span>操作pȝ的信号量是个很重要的概念Q在q程控制斚w都有应用。Java q发?的Semaphore 可以很轻村֮成信号量控制QSemaphore可以控制某个资源可被同时讉K的个敎ͼ通过 acquire() 获取一个许可,如果没有q待,?release() 释放一个许可。比如在Windows下可以设|共享文件的最大客L讉K个数?nbsp;
Semaphore实现的功能就cM厕所?个坑Q假如有10个h要上厕所Q那么同时只能有多少个hM厕所呢?同时只能?个h能够占用Q当5个h?的Q何一个h让开后,其中{待的另?个h中又有一个h可以占用了。另外等待的5个h中可以是随机获得优先ZQ也可以是按照先来后到的序获得ZQ这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能Qƈ且可以是׃个线E获得了“?#8221;Q再由另一个线E释?#8220;?#8221;Q这可应用于死锁恢复的一些场合?br /> Semaphorel护了当前访问的个数Q提供同步机Ӟ控制同时讉K的个数。在数据l构中链表可以保?#8220;无限”的节点,用Semaphore可以实现有限大小的链表。另外重入锁 ReentrantLock 也可以实现该功能Q但实现上要复杂些?nbsp;
下面的Demo中申明了一个只?个许可的SemaphoreQ而有20个线E要讉Kq个资源Q通过acquire()和release()获取和释放访问许可?/p>
package com.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class TestSemaphore {
public static void main(String[] args) {
// U程?/span>
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线E同时访?/span>
final Semaphore semp = new Semaphore(5);
// 模拟20个客L讉K
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
// 讉K完后Q释?/span>
semp.release();
System.out.println("-----------------"+semp.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
// 退出线E池
exec.shutdown();
}
}
执行l果如下Q?/span>
Accessing: 0
Accessing: 1
Accessing: 3
Accessing: 4
Accessing: 2
-----------------0
Accessing: 6
-----------------1
Accessing: 7
-----------------1
Accessing: 8
-----------------1
Accessing: 10
-----------------1
Accessing: 9
-----------------1
Accessing: 5
-----------------1
Accessing: 12
-----------------1
Accessing: 11
-----------------1
Accessing: 13
-----------------1
Accessing: 14
-----------------1
Accessing: 15
-----------------1
Accessing: 16
-----------------1
Accessing: 17
-----------------1
Accessing: 18
-----------------1
Accessing: 19
http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html ]]>Javaq发包中的几UExecutorService http://www.aygfsteel.com/stevenjohn/archive/2012/12/19/393203.htmlabin abin Wed, 19 Dec 2012 04:39:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/12/19/393203.html http://www.aygfsteel.com/stevenjohn/comments/393203.html http://www.aygfsteel.com/stevenjohn/archive/2012/12/19/393203.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/393203.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/393203.html 1.CachedThreadPool
CachedThreadPool首先会按照需要创够多的线E来执行d(Task)。随着E序执行的过E,有的U程执行完了dQ可以被重新循环使用Ӟ才不再创建新的线E来执行d。我们采用《Thinking In Java》中的例子来分析?/p>
首先QQ务定义如?实现了Runnable接口Qƈ且复写了runҎ)Q?/p>
package net.jerryblog.concurrent; public class LiftOff implements Runnable{ protected int countDown = 10; //Default private static int taskCount = 0; private final int id = taskCount++; public LiftOff() {} public LiftOff(int countDown) { this.countDown = countDown; } public String status() { return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + ") "; } @Override public void run() { while(countDown-- > 0) { System.out.print(status()); Thread.yield(); } } } 采用CachedThreadPool方式执行~写的客LE序如下Q?nbsp; package net.jerryblog.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CachedThreadPool { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for(int i = 0; i < 10; i++) { exec.execute(new LiftOff()); } exec.shutdown(); } } 上面的程序中Q有10个Q务,采用CachedThreadPool模式Qexec没遇C个LiftOff的对?Task)Q就会创Z个线E来处理d。现在假N到到W?个Q务时Q之前用于处理第一个Q务的U程已经执行完成d了,那么不会创徏新的U程来处理Q务,而是使用之前处理W一个Q务的U程来处理这W?个Q务。接着如果遇到W?个Q务时Q前面那些Q务都q没有执行完Q那么就会又新创建线E来执行W?个Q务。否则,使用之前执行完Q务的U程来处理新的Q务?
2.FixedThreadPool
FixedThreadPool模式会用一个优先固定数目的U程来处理若q数目的d。规定数目的U程处理所有Q务,一旦有U程处理完了d׃被用来处理新的Q?如果有的?。这U模式与上面的CachedThreadPool是不同的QCachedThreadPool模式下处理一定数量的d的线E数目是不确定的。而FixedThreadPool模式?span style="color: #ff0000">最?/span> 的线E数目是一定的?/p>
采用FixedThreadPool模式~写客户端程序如下:
package net.jerryblog.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FixedThreadPool { public static void main(String[] args) { //三个U程来执行五个Q? ExecutorService exec = Executors.newFixedThreadPool(3); for(int i = 0; i < 5; i++) { exec.execute(new LiftOff()); } exec.shutdown(); } }
3.SingleThreadExecutor模式
SingleThreadExecutor模式只会创徏一个线E。它和FixedThreadPool比较cMQ不q线E数是一个。如果多个Q务被提交lSingleThreadExecutor的话Q那么这些Q务会被保存在一个队列中Qƈ且会按照d提交的顺序,一个先执行完成再执行另外一个线E?/p>
SingleThreadExecutor模式可以保证只有一个Q务会被执行。这U特点可以被用来处理׃n资源的问题而不需要考虑同步的问题?/p>
SingleThreadExecutor模式~写的客LE序如下Q?nbsp;
package net.jerryblog.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SingleThreadExecutor { public static void main(String[] args) { ExecutorService exec = Executors.newSingleThreadExecutor(); for (int i = 0; i < 2; i++) { exec.execute(new LiftOff()); } } } q种模式下执行的l果如下Q?br />#0(9) #0(8) #0(7) #0(6) #0(5) #0(4) #0(3) #0(2) #0(1) #0(LiftOff!) #1(9) #1(8) #1(7) #1(6) #1(5) #1(4) #1(3) #1(2) #1(1) #1(LiftOff!) W一个Q务执行完了之后才开始执行第二个d?span style="font-size: 12px"> ]]>java多线E?q回l果 http://www.aygfsteel.com/stevenjohn/archive/2012/12/07/392585.htmlabin abin Fri, 07 Dec 2012 02:36:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/12/07/392585.html http://www.aygfsteel.com/stevenjohn/comments/392585.html http://www.aygfsteel.com/stevenjohn/archive/2012/12/07/392585.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/392585.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/392585.html
package com.abin.lee.thread;
import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class ThreadSync{ public static List<Object> ThreadSync(final String message) throws InterruptedException{ final List<Object> list=new LinkedList<Object>(); Thread thread=new Thread(){ public void run(){ if(message.equals("one")){ list.add(0, message); } } }; thread.start(); thread.join(); return list; } public static void main(String[] args) throws InterruptedException { List<Object> list=ThreadSync("one1"); System.out.println("size="+list.size()); for(Iterator it=list.iterator();it.hasNext();){ Object obj=(Object)it.next(); System.out.println("obj="+obj); } } } Ҏ二:
]]> 如何快速处理十万条数据到数据库 http://www.aygfsteel.com/stevenjohn/archive/2012/12/05/392451.htmlabin abin Tue, 04 Dec 2012 16:54:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/12/05/392451.html http://www.aygfsteel.com/stevenjohn/comments/392451.html http://www.aygfsteel.com/stevenjohn/archive/2012/12/05/392451.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/392451.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/392451.html 如何快速处理十万条数据到数据库 ]]> javaȝE唤醒子U程的疑?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391484.htmlabin abin Fri, 16 Nov 2012 17:38:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391484.html http://www.aygfsteel.com/stevenjohn/comments/391484.html http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391484.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/391484.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/391484.html
public class Example{ public static void main(String args[]){ A target=new A(); //U程thread的目标对?nbsp; Thread thread=new Thread(target); thread.setName("张三"); thread.start(); while(target.getStop()==false){} System.out.println("我是ȝE?负责恢复"+thread.getName()+"U程"); target.restart(); //恢复threadU程 } } class A implements Runnable{ int number=0; boolean stop=false; boolean getStop(){ return stop; } public void run(){ while(true){ number++; System.out.println(Thread.currentThread().getName()+"的number="+number); if(number==3){ try{ System.out.println(Thread.currentThread().getName()+"被挂?); stop=true; hangUP();//挂vU程 System.out.println(Thread.currentThread().getName()+"恢复执行"); } catch(Exception e){} } try{ Thread.sleep(1000); } catch(Exception e){} } } public synchronized void hangUP() throws InterruptedException{ wait(); } public synchronized void restart(){ notifyAll(); } }求教QmainҎ中的I@环是做什么用的?初学U程Q不是很理解?/span>while(target.getStop()==false){} {待targetU程l束QtargetU程q行在主U程main里面Q如果没有这个空循环Q主U程序执行Qtargetq没有执行完得时候主U程已经执行完退ZQ会Dtarget也退出?/span>
]]> java wait()与notify() http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391483.htmlabin abin Fri, 16 Nov 2012 17:01:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391483.html http://www.aygfsteel.com/stevenjohn/comments/391483.html http://www.aygfsteel.com/stevenjohn/archive/2012/11/17/391483.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/391483.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/391483.html 下面的例子通过wait() 来取代忙{待机制Q当收到通知消息Ӟ notify 当前 Monitor cȝE?/span>
package com.abin.lee.servlet.mythread.runnable;
import java.util.concurrent.TimeUnit;
public class MyObject implements Runnable{
private Monitor monitor;
public MyObject(Monitor monitor) {
this.monitor=monitor;
}
public void run(){
try {
System.out.println("beforeTimeUnit.SECONDS="+System.currentTimeMillis());
TimeUnit.SECONDS.sleep(3);
System.out.println("i am going");
monitor.getMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.abin.lee.servlet.mythread.runnable;
public class Monitor implements Runnable{
private volatile boolean go=false;
public synchronized void getMessage(){
System.out.println("beforenotify getMessage="+System.currentTimeMillis());
go=true;
notify();
System.out.println("afternotify getMessage="+System.currentTimeMillis());
}
public synchronized void watching() throws InterruptedException{
System.out.println("beforewait watching="+System.currentTimeMillis());
while(go==false)
wait();
System.out.println("he has gone");
}
public void run(){
try {
watching();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.abin.lee.servlet.mythread.runnable;
public class Wait {
public static void main(String[] args) {
Monitor monitor=new Monitor();
MyObject obj=new MyObject(monitor);
new Thread(obj).start();
new Thread(monitor).start();
}
}
]]> Java中是不是父线E阻塞后子线E就无法l箋执行Q?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/11/16/391480.htmlabin abin Fri, 16 Nov 2012 13:43:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/11/16/391480.html http://www.aygfsteel.com/stevenjohn/comments/391480.html http://www.aygfsteel.com/stevenjohn/archive/2012/11/16/391480.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/391480.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/391480.html Java中是不是父线E阻塞后子线E就无法l箋执行Q?/span> 如果不是Q该如何实现d父线E但l箋执行子线E? 不是Q这个问题属于线E调度?br />让一个线E明的l另外一个线E运行机会,采用以下ҎQ?br />1.调整U程优先U?br />2.让处于运行状态的U程调用Thread.sleepQ)Ҏ 3.让处于运行状态的U程调用Thread.yieldQ)Ҏ 4.让处于运行状态的U程调用另外一个线E的jionQ)Ҏ ]]> 多线E题? http://www.aygfsteel.com/stevenjohn/archive/2012/11/09/391119.htmlabin abin Fri, 09 Nov 2012 13:37:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/11/09/391119.html http://www.aygfsteel.com/stevenjohn/comments/391119.html http://www.aygfsteel.com/stevenjohn/archive/2012/11/09/391119.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/391119.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/391119.html 看到一个题目:针对下面的程序,写出magicҎ 让整个程序只打印出step1,step2 不打印step3 public static void enter(Object obj) { System.out.println("Step 1"); try { magic1(obj); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Step 2"); synchronized (obj) { System.out.println("Step 3 (never reached here)"); } }
题目的意思很Ҏ理解Q可是要做出q道题目需要对多线E的基本改进非常的理解?/p>
下面列出基本思\Q?/p>
ȝE想获取obj 的锁Q但是获取不刎ͼ说明子线E始l在占据着q个对象的锁?/p>
同时ȝE又能返回?/p>
那现在就要实现让子线E先跑,然后再唤醒主U程。这个显然是锁的占有和唤醒,那么问题来了Q将什么做个锁呢?如果?span style="font-size: 10pt">obj的话Q不可能Q因为子U程昄不能在放?span style="font-size: 10pt">obj.
那么只能是子U程自己的锁?/p>
下边是程?/p> static void magic1(final Object obj) throws Exception{ final Thread t = new Thread(){ public void run(){ synchronized(this){ synchronized(obj){ try { notify(); join(); } catch (InterruptedException e) { } } } } }; synchronized(t){ t.start(); t.wait(); } }
]]>Java 多线E?加到100 http://www.aygfsteel.com/stevenjohn/archive/2012/11/05/390843.htmlabin abin Mon, 05 Nov 2012 14:40:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/11/05/390843.html http://www.aygfsteel.com/stevenjohn/comments/390843.html http://www.aygfsteel.com/stevenjohn/archive/2012/11/05/390843.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/390843.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/390843.html package com.abin.lee.servlet.mythread.runnable;
import java.util.concurrent.atomic.AtomicInteger;
public class SumThread implements Runnable{ private AtomicInteger num=new AtomicInteger(0); public void run(){ while(num.get()<100){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(num.get()==40){ Thread thread2=new Thread(this,"thread2"); thread2.start(); } System.out.println(Thread.currentThread().getName()+":"+num.getAndIncrement()); } } }
package com.abin.lee.servlet.mythread.runnable;
public class SumThreadTest { public static void main(String[] args) { SumThread ru=new SumThread(); Thread thread1=new Thread(ru,"thread1"); thread1.start(); } }
]]> Java volatile(一) http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389795.htmlabin abin Thu, 18 Oct 2012 02:38:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389795.html http://www.aygfsteel.com/stevenjohn/comments/389795.html http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389795.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/389795.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/389795.html Volatile修饰的成员变量在每次被线E访问时Q都从共享内存中重读该成员变量的倹{而且Q当成员变量发生变化ӞU程变化值回写到׃n内存。这样在M时刻Q?/pre>两个不同的线EL看到某个成员变量的同一个倹{?
Java语言规范中指出:Z获得最佳速度Q允许线E保存共享成员变量的U有拯Q而且只当U程q入或者离开同步代码块时才与׃n成员变量的原始值对比?
q样当多个线E同时与某个对象交互Ӟ必要注意到要让线E及时的得到׃n成员变量的变化?
而volatile关键字就是提CVMQ对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互?
使用Q在两个或者更多的U程讉K的成员变量上使用volatile。当要访问的变量已在synchronized代码块中Q或者ؓ帔RӞ不必使用?
׃使用volatile屏蔽掉了VM中必要的代码优化Q所以在效率上比较低Q因此一定在必要时才使用此关键字?
pC中的一?止~译器进行优化~~~~ 在ƈ发中可保证内存一致?br />volatile声明的变量只在主存中存储 d的时候,会有d脏数据的情况发生 但是写数据的时候,是能保证数据能正写?br /> volatile只保证每ơ都从主存拿数据Q其他保证不了什么吧Q?br />告诉~译器不要用缓?br /> 非long、double变量不能保证原子性,非volatile变量不能保证内存可见性?br /> volatile q能防止reorder... 是内存屏蔽Q防止指令重?br />其实目的是保证可见?br />可以操作volatile...变量 但是不代表你的操作指令是原子?br /> ]]> java中volatile关键字的含义 http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389796.htmlabin abin Thu, 18 Oct 2012 02:38:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389796.html http://www.aygfsteel.com/stevenjohn/comments/389796.html http://www.aygfsteel.com/stevenjohn/archive/2012/10/18/389796.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/389796.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/389796.html
在javaU程q发处理中,有一个关键字volatile的用目前存在很大的hQ以Z用这个关键字Q在q行多线Eƈ发处理的时候就可以万事大吉?/p>
Java语言是支持多U程的,Z解决U程q发的问题,在语a内部引入?同步??volatile 关键字机制?/p>
synchronized
同步块大安比较熟悉Q通过 synchronized 关键字来实现Q所有加上synchronized ?块语句,在多U程讉K的时候,同一时刻只能有一个线E能够用
synchronized 修饰的方?或?代码块?/p>
volatile
用volatile修饰的变量,U程在每ơ用变量的时候,都会d变量修改后的最的倹{volatile很容易被误用Q用来进行原子性操作?/p>
下面看一个例子,我们实现一个计数器Q每ơ线E启动的时候,会调用计数器incҎQ对计数器进行加一
执行环境——jdk版本Qjdk1.6.0_31 Q内?Q?G cpuQx86 2.4G
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
public
class
Counter {
public
static
int
count =
0
;
public
static
void
inc() {
try
{
Thread.sleep(
1
);
}
catch
(InterruptedException e) {
}
count++;
}
public
static
void
main(String[] args) {
for
(
int
i =
0
; i <
1000
; i++) {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
Counter.inc();
}
}).start();
}
System.out.println(
"q行l果:Counter.count="
+ Counter.count);
}
}
1
实际q算l果每次可能都不一P本机的结果ؓQ运行结?Counter.count=
995
Q可以看出,在多U程的环境下QCounter.countq没有期望结果是
1000
1
很多Z为,q个是多U程q发问题Q只需要在变量count之前加上
volatile
可以避免这个问题,那我们在修改代码看看Q看看结果是不是W合我们的期?/code>
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
public
class
Counter {
public
volatile
static
int
count =
0
;
public
static
void
inc() {
try
{
Thread.sleep(
1
);
}
catch
(InterruptedException e) {
}
count++;
}
public
static
void
main(String[] args) {
for
(
int
i =
0
; i <
1000
; i++) {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
Counter.inc();
}
}).start();
}
System.out.println(
"q行l果:Counter.count="
+ Counter.count);
}
}
q行l果:Counter.count=992
q行l果q是没有我们期望?000Q下面我们分析一下原?/p>
?java 垃圾回收整理一文中Q描qCjvmq行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈Q每一个线E运行时都有一个线E栈Q?/p>
U程栈保存了U程q行时候变量g息。当U程讉K某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的|然后把堆内存
变量的具体值load到线E本地内存中Q徏立一个变量副本,之后U程׃再和对象在堆内存变量值有M关系Q而是直接修改副本变量的|
在修改完之后的某一个时刻(U程退Z前)Q自动把U程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一q图
描述q写交互
read and load 从主存复制变量到当前工作内存 use and assign 执行代码Q改变共享变量? store and write 用工作内存数据刷C存相兛_?/p>
其中use and assign 可以多次出现
但是q一些操作ƈ不是原子性,也就?在read load之后Q如果主内存count变量发生修改之后Q线E工作内存中的值由于已l加载,不会产生对应的变化,所以计出来的l果会和预期不一?/p>
对于volatile修饰的变量,jvm虚拟机只是保证从d存加载到U程工作内存的值是最新的
例如假如U程1Q线E? 在进行read,load 操作中,发现d存中count的值都?Q那么都会加载这个最新的?/p>
在线E?堆countq行修改之后Q会writeC内存中,d存中的count变量׃变ؓ6
U程2׃已经q行read,load操作Q在q行q算之后Q也会更C内存count的变量gؓ6
D两个U程及时用volatile关键字修改之后,q是会存在ƈ发的情况?/p>
]]> Java 三种方式实现多线E?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/10/12/389493.htmlabin abin Fri, 12 Oct 2012 15:41:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/10/12/389493.html http://www.aygfsteel.com/stevenjohn/comments/389493.html http://www.aygfsteel.com/stevenjohn/archive/2012/10/12/389493.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/389493.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/389493.html W一U:QThreadQ?/span>
package com.abin.lee.servlet.mythread.thread;
public class Mythread extends Thread{ private String name; public Mythread(String name) { this.name=name; } public void run() { synchronized(this.name){ System.out.println("开始时_"+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); System.out.println("name="+name); System.out.println("l束旉Q?+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); } } }
试代码Q?/span>
package com.abin.lee.servlet.mythread.thread;
public class MythreadTest { public static void main(String[] args) { Mythread mythread1=new Mythread("ManyThread"); Mythread mythread2=new Mythread("ManyThread"); mythread1.start(); mythread2.start(); }
}
W二U:QRunnableQ?/span>
package com.abin.lee.servlet.mythread.runnable;
public class MyRunnable implements Runnable{ private String name; public MyRunnable(String name) { this.name=name; } public synchronized void run(){ System.out.println("开始时_"+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); System.out.println("name="+name); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("l束旉Q?+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); } }
试代码Q?/span>
package com.abin.lee.servlet.mythread.runnable;
public class MyRunnableTest { public static void main(String[] args) { MyRunnable myRunnable=new MyRunnable("ManyThread"); Thread thread1=new Thread(myRunnable); Thread thread2=new Thread(myRunnable); thread1.start(); thread2.start(); } }
W三U:QCallableQ这U说明一下,q个实现多线E的方式是在JDK1.5引进的,在java.util.concurrent.Callable q个q发包下面,q且提供同步q回l果的多U程?/span>
package com.abin.lee.servlet.mythread.callable;
import java.util.concurrent.Callable; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class MyCallable implements Callable<String>{ private String name; public MyCallable(String name) { this.name=name; } public String call() throws Exception { Lock lock=new ReentrantLock(); lock.lock(); String result=""; try { System.out.println("开始时_"+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); System.out.println("name="+name); if(name.equals("ManyThread")){ result="success"; }else{ result="failure"; } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("l束旉Q?+System.currentTimeMillis()+",U程名字Q?+Thread.currentThread().getName()); } catch (Exception e) { e.printStackTrace(); }finally{ lock.unlock(); } return result; } }
试代码Q?/span>
package com.abin.lee.servlet.mythread.callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;
import org.junit.Test;
public class MyCallableTest { @Test public void testMyCallable() throws InterruptedException, ExecutionException{ ExecutorService executor=Executors.newFixedThreadPool(3); MyCallable myCallable=new MyCallable("ManyThread"); Future future1=executor.submit(myCallable); System.out.println("future1="+future1.get()); Future future2=executor.submit(myCallable); System.out.println("future2="+future2.get()); Future future3=executor.submit(myCallable); System.out.println("future3="+future3.get()); }
} 试l果Q?br />
开始时_1350056647659,U程名字Qpool-1-thread-1
name=ManyThread
l束旉Q?350056650661,U程名字Qpool-1-thread-1
future1=success
开始时_1350056650661,U程名字Qpool-1-thread-2
name=ManyThread
l束旉Q?350056653661,U程名字Qpool-1-thread-2
future2=success
开始时_1350056653662,U程名字Qpool-1-thread-3
name=ManyThread
l束旉Q?350056656663,U程名字Qpool-1-thread-3
future3=success
]]> Java ThreadLocal<Connection> http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386757.htmlabin abin Sat, 01 Sep 2012 09:03:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386757.html http://www.aygfsteel.com/stevenjohn/comments/386757.html http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386757.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/386757.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/386757.html //ThreadLocalW一U用法: //Q?br />-- Create table
create table USERBEAN
(
ID NVARCHAR2(40) not null,
USERNAME NVARCHAR2(40),
PASSWORD NVARCHAR2(40)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table USERBEAN
add constraint SSSID primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
package com.abin.lee.collection.threadlocal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MyThreadLocal {
//使用ThreadLocal保存Connection变量
public static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
private static final String URL = "jdbc:oracle:thin:@localhost:1521:XE";
private static final String USERNAME = "abing";
private static final String PWD = "abing";
public static Connection getConnection() {
Connection connection = null;
String url = "";
//如果connThreadLocal没有本线E对应的Connection创徏一个新的ConnectionQƈ其保存到线E本地变量中?/div>
if (threadLocal.get() == null) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
connection = DriverManager.getConnection(URL, USERNAME, PWD);
threadLocal.set(connection);
} catch (Exception e) {
e.printStackTrace();
}
}else {
return threadLocal.get();//直接q回U程本地变量
}
return connection;
}
public static void remove() {
threadLocal.remove();
}
}
package com.abin.lee.collection.threadlocal;
import java.io.Serializable;
public class UserBean implements Serializable{
private String id;
private String username;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
//试代码
package com.abin.lee.collection.threadlocal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class OracleOperate {
public static List<UserBean> findAll(){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String sql="select * from userbean order by id desc";
List<UserBean> list=new ArrayList<UserBean>();
UserBean user=null;
try {
conn=MyThreadLocal.getConnection();
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while (rs.next()&&rs!=null) {
user=new UserBean();
user.setId(rs.getString("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
list.add(user);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
public static void main(String[] args) {
List<UserBean> list=findAll();
for(UserBean lst:list){
System.out.println("id="+lst.getId());
System.out.println("username="+lst.getUsername());
System.out.println("id="+lst.getPassword());
}
}
}
//ThreadLocalW二U用法:
package com.abin.lee.collection.threadlocal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MyThreadLocal {
private static final String URL = "jdbc:oracle:thin:@localhost:1521:XE";
private static final String USERNAME = "abing";
private static final String PWD = "abing";
//使用ThreadLocal保存Connection变量
public static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(){
protected Connection initialValue() {
Connection connection = null;
//如果connThreadLocal没有本线E对应的Connection创徏一个新的ConnectionQƈ其保存到线E本地变量中?/div>
if (connection == null) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
connection = DriverManager.getConnection(URL, USERNAME, PWD);
} catch (Exception e) {
e.printStackTrace();
}
}
return connection;
}
};
public static Connection getConnection() {
return threadLocal.get();
}
public static void remove() {
threadLocal.remove();
}
}
package com.abin.lee.collection.threadlocal;
import java.io.Serializable;
public class UserBean implements Serializable{
private String id;
private String username;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.abin.lee.collection.threadlocal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class OracleOperate {
public static List<UserBean> findAll(){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String sql="select * from userbean order by id desc";
List<UserBean> list=new ArrayList<UserBean>();
UserBean user=null;
try {
conn=MyThreadLocal.getConnection();
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while (rs.next()&&rs!=null) {
user=new UserBean();
user.setId(rs.getString("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
list.add(user);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
public static void main(String[] args) {
List<UserBean> list=findAll();
for(UserBean lst:list){
System.out.println("id="+lst.getId());
System.out.println("username="+lst.getUsername());
System.out.println("id="+lst.getPassword());
}
}
}
]]>
Java Volatile操作多线E?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386753.htmlabin abin Sat, 01 Sep 2012 07:56:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386753.html http://www.aygfsteel.com/stevenjohn/comments/386753.html http://www.aygfsteel.com/stevenjohn/archive/2012/09/01/386753.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/386753.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/386753.html package com.abin.lee.collection.volatiler;
public class MyThread implements Runnable{
private volatile boolean flag=false;
public void run() {
while(!flag){
try {
System.out.println("before");
Thread.sleep(3000);
System.out.println("after");
} catch (Exception e) {
e.printStackTrace();
}
flag=true;
}
}
public void setDone(boolean flag){
this.flag=flag;
}
}
试代码Q?br />
package com.abin.lee.collection.volatiler;
public class MyVolatileOne {
public static void main(String[] args) {
MyThread myThread=new MyThread();
Thread thread=new Thread(myThread);
thread.start();
}
}
]]>
Java 多线E?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/08/02/384611.htmlabin abin Thu, 02 Aug 2012 07:30:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/08/02/384611.html http://www.aygfsteel.com/stevenjohn/comments/384611.html http://www.aygfsteel.com/stevenjohn/archive/2012/08/02/384611.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/384611.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/384611.html
问题解决2——加入{待与唤?/strong>
package edu.sjtu.erplab.thread;
class Info{ private String name="name"; private String content="content"; private boolean flag=true; public synchronized void set(String name,String content) { if(!flag)//标志位ؓfalseQ不可以生 { try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.setName(name); try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.setContent(content); flag=false;//修改标志位ؓfalseQ表C生产者已l完成资源,消费者可以消贏V?br /> super.notify();//唤醒消费者进E?br /> } public synchronized void get() { if(flag) { try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.getName()+":-->"+this.getContent()); flag=true;//修改标志位ؓtrueQ表C消费者拿走资源,生者可以生产?br /> super.notify();//唤醒生者进E?br /> } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
class Producer implements Runnable{ private Info info=null; public Producer(Info info) { this.info=info; }
@Override public void run() { boolean flag=false; for(int i=0;i<10;i++) if(flag) { this.info.set("name+"+i, "content+"+i); flag=false; } else { this.info.set("name-"+i, "content-"+i); flag=true; } } }
class Consumer implements Runnable{ private Info info=null; public Consumer(Info info) { this.info=info; } @Override public void run() { for(int i=0;i<10;i++) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.get(); } } }
public class ThreadDeadLock { public static void main(String args[]) { Info info=new Info(); Producer pro=new Producer(info); Consumer con=new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } }http://www.cnblogs.com/xwdreamer/archive/2011/11/20/2296931.html#2397397
]]> _的JavaU程Sleep,yield,wait,notify,Synchronized http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380945.htmlabin abin Sat, 16 Jun 2012 17:42:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380945.html http://www.aygfsteel.com/stevenjohn/comments/380945.html http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380945.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/380945.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/380945.html U程Q是指进E中的一个执行流E? U程与进E的区别Q每个进E都需要操作系lؓ其分配独立的内存地址I间Q而同一q程中的所有线E在同一块地址I间中工作,q些U程可以׃n同一块内存和pȝ资源? 如何创徏一个线E? 创徏U程有两U方式,如下Q? 1?扩展java.lang.Threadc? 2?实现Runnable接口 ThreadcM表线E类Q它的两个最主要的方法是Q? run()——包含U程q行时所执行的代? Start()——用于启动U程 一个线E只能被启动一ơ。第二次启动时将会抛出java.lang.IllegalThreadExcetpion异常 U程间状态的转换Q如囄Q? 新徏状态:用new语句创徏的线E对象处于新建状态,此时它和其它的java对象一P仅仅在堆中被分配了内? qA状态:当一个线E创Z以后Q其他的U程调用了它的start()ҎQ该U程p入了qA状态。处于这个状态的U程位于可运行池中,{待获得CPU的用权 q行状态:处于q个状态的U程占用CPU,执行E序的代? d状态:当线E处于阻塞状态时Qjava虚拟Z会给U程分配CPUQ直到线E重新进入就l状态,它才有机会{到运行状态? d状态分ZU情况: 1?位于对象{待池中的阻塞状态:当线E运行时Q如果执行了某个对象的wait()ҎQjava虚拟机就回把U程攑ֈq个对象的等待池? 2?位于对象锁中的阻塞状态,当线E处于运行状态时Q试图获得某个对象的同步锁时Q如果该对象的同步锁已经被其他的U程占用QJVM׃把这个线E放到这个对象的琐池中? 3?其它的阻塞状态:当前U程执行了sleep()ҎQ或者调用了其它U程的join()ҎQ或者发ZI/OhӞ׃q入q个状态中? M状态:当线E退Zrun()ҎQ就q入了死亡状态,该线E结束了生命周期? 或者正帔R? 或者遇到异帔R? ThreadcȝisAlive()Ҏ判断一个线E是否活着Q当U程处于M状态或者新建状态时Q该Ҏq回false,在其余的状态下Q该Ҏq回true. U程调度 U程调度模型Q分时调度模型和抢占式调度模? JVM采用抢占式调度模型? 所谓的多线E的q发q行Q其实是指宏观上看,各个U程轮流获得CPU的用权Q分别执行各自的d? Q线E的调度不是跨^収ͼ它不仅取决于java虚拟机,它还依赖于操作系l) 如果希望明确地让一个线E给另外一个线E运行的ZQ可以采取以下的办法之一 1?调整各个U程的优先 2?让处于运行状态的U程调用Thread.sleep()Ҏ 3?让处于运行状态的U程调用Thread.yield()Ҏ 4?让处于运行状态的U程调用另一个线E的join()Ҏ 调整各个U程的优先 ThreadcȝsetPriority(int)和getPriority()Ҏ分别用来讄优先U和d优先U? 如果希望E序能够Ud到各个操作pȝ中,应该保在设|线E的优先U时Q只使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITYq?个优先? U程睡眠Q当U程在运行中执行了sleep()ҎӞ它就会放弃CPUQ{到阻塞状态? U程让步Q当U程在运行中执行了Threadcȝyield()静态方法时Q如果此时具有相同优先的其它线E处于就l状态,那么yield()Ҏ把当前q行的线E放到运行池中ƈ使另一个线E运行。如果没有相同优先的可q行U程Q则yield()Ҏ什么也不做? Sleep()Ҏ和yield()Ҏ都是Threadcȝ静态方法,都会使当前处于运行状态的U程攑ּCPUQ把q行Z让给别的U程Q两者的区别在于Q? 1、sleep()Ҏ会给其他U程q行的机会,而不考虑其他U程的优先Q因此会l较低线E一个运行的ZQyield()Ҏ只会l相同优先或者更高优先的线E一个运行的Z? 2、当U程执行了sleep(long millis)Ҏ后,{到阻塞状态,参数millis指定睡眠旉Q当U程执行了yield()Ҏ后,{到就l状态? 3、sleep()Ҏ声明抛出InterruptedException异常Q而yield()Ҏ没有声明抛出M异常 4、sleep()Ҏ比yield()Ҏh更好的移植? {待其它U程的结束:join() 当前q行的线E可以调用另一个线E的 join()ҎQ当前运行的U程{到阻塞状态,直到另一个线E运行结束,它才恢复q行? 定时器Timer:在JDK的java.util包中提供了一个实用类Timer, 它能够定时执行特定的d? U程的同? 原子操作Q根据Java规范Q对于基本类型的赋值或者返回值操作,是原子操作。但q里的基本数据类型不包括long和double, 因ؓJVM看到的基本存储单位是32位,而long 和double都要?4位来表示。所以无法在一个时钟周期内完成? 自增操作Q?+Q不是原子操作,因ؓ它涉及到一ơ读和一ơ写? 原子操作Q由一l相关的操作完成Q这些操作可能会操纵与其它的U程׃n的资源,Z保证得到正确的运结果,一个线E在执行原子操作光Q应该采取其他的措施使得其他的线E不能操U共享资源? 同步代码块:Z保证每个U程能够正常执行原子操作QJava引入了同步机Ӟ具体的做法是在代表原子操作的E序代码前加上synchronized标记Q这L代码被称为同步代码块? 同步锁:每个JAVA对象都有且只有一个同步锁Q在M时刻Q最多只允许一个线E拥有这把锁? 当一个线E试图访问带有synchronized(this)标记的代码块Ӟ必须获得 this关键字引用的对象的锁Q在以下的两U情况下Q本U程有着不同的命q? 1?假如q个锁已l被其它的线E占用,JVM׃把这个线E放到本对象的锁池中。本U程q入d状态。锁池中可能有很多的U程Q等到其他的U程释放了锁QJVM׃从锁池中随机取出一个线E,使这个线E拥有锁Qƈ且{到就l状态? 2?假如q个锁没有被其他U程占用Q本U程会获得这把锁Q开始执行同步代码块? Q一般情况下在执行同步代码块时不会释攑步锁Q但也有Ҏ情况会释攑֯象锁 如在执行同步代码块时Q遇到异常而导致线E终止,锁会被释放;在执行代码块Ӟ执行了锁所属对象的wait()ҎQ这个线E会释放对象锁,q入对象的等待池中) U程同步的特征: 1?如果一个同步代码块和非同步代码块同时操作共享资源,仍然会造成对共享资源的竞争。因为当一个线E执行一个对象的同步代码块时Q其他的U程仍然可以执行对象的非同步代码块。(所谓的U程之间保持同步Q是指不同的U程在执行同一个对象的同步代码块时Q因获得对象的同步锁而互相牵Ӟ 2?每个对象都有唯一的同步锁 3?在静态方法前面可以用synchronized修饰W? 4?当一个线E开始执行同步代码块Ӟq不意味着必须以不间断的方式运行,q入同步代码块的U程可以执行Thread.sleep()或者执行Thread.yield()ҎQ此时它q不释放对象锁,只是把运行的Z让给其他的线E? 5?Synchronized声明不会被承,如果一个用synchronized修饰的方法被子类覆盖Q那么子cMq个Ҏ不在保持同步Q除非用synchronized修饰? U程安全的类Q? 1?q个cȝ对象可以同时被多个线E安全的讉K? 2?每个U程都能正常的执行原子操作,得到正确的结果? 3?在每个线E的原子操作都完成后Q对象处于逻辑上合理的状态? 释放对象的锁Q? 1?执行完同步代码块׃释放对象的锁 2?在执行同步代码块的过E中Q遇到异常而导致线E终止,锁也会被释放 3?在执行同步代码块的过E中Q执行了锁所属对象的wait()ҎQ这个线E会释放对象锁,q入对象的等待池? 死锁 当一个线E等待由另一个线E持有的锁,而后者正在等待已被第一个线E持有的锁时Q就会发生死锁。JVM不监也不试N免这U情况,因此保证不发生死锁就成了E序员的责Q? 如何避免死锁 一个通用的经验法则是Q当几个U程都要讉K׃n资源A、B、C Ӟ保证每个U程都按照同L序去访问他们? U程通信 Java.lang.ObjectcM提供了两个用于线E通信的方? 1?wait():执行了该Ҏ的线E释攑֯象的锁,JVM会把该线E放到对象的{待池中。该U程{待其它U程唤醒 2?notify():执行该方法的U程唤醒在对象的{待池中{待的一个线E,JVM从对象的{待池中随机选择一个线E,把它转到对象的锁池中?img src ="http://www.aygfsteel.com/stevenjohn/aggbug/380945.html" width = "1" height = "1" /> ]]> java U程的四U状?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380944.htmlabin abin Sat, 16 Jun 2012 17:41:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380944.html http://www.aygfsteel.com/stevenjohn/comments/380944.html http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380944.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/380944.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/380944.html
来自Q开发者在U?
Java多线E程序设计详l解?
一、理解多U程
多线E是q样一U机Ӟ它允许在E序中ƈ发执行多个指令流Q每个指令流都称Z个线E,彼此间互相独立?
U程又称量q程Q它和进E一h有独立的执行控制Q由操作pȝ负责调度Q区别在于线E没有独立的存储I间Q而是和所属进E中的其它线E共享一个存储空_q得线E间的通信q较q程单?
多个U程的执行是q发的,也就是在逻辑?#8220;同时”Q而不是否是物理上的“同时”。如果系l只有一个CPUQ那么真正的“同时”是不可能的,但是׃CPU的速度非常快,用户感觉不到其中的区别,因此我们也不用关心它Q只需要设惛_个线E是同时执行卛_?
多线E和传统的单U程在程序设计上最大的区别在于Q由于各个线E的控制彼此独立,使得各个U程之间的代码是乱序执行的,由此带来的线E调度,同步{问题,在以后探讨?
二:在Java中实现多U程
我们不妨设想Qؓ了创Z个新的线E,我们需要做些什么?很显Ӟ我们必须指明q个U程所要执行的代码Q而这是在Java中实现多U程我们所需要做的一切!
真是奇QJava是如何做到这一点的Q通过c!作ؓ一个完全面向对象的语言QJava提供了类java.lang.Thread来方便多U程~程Q这个类提供了大量的Ҏ来方便我们控制自q各个U程Q我们以后的讨论都将围绕q个c进行?
那么如何提供l?Java 我们要线E执行的代码呢?让我们来看一?Thread cRThread cL重要的方法是run()Q它为ThreadcȝҎstart()所调用Q提供我们的U程所要执行的代码。ؓ了指定我们自q代码Q只需要覆盖它Q?
Ҏ一Q?Thread c,覆盖Ҏ run()Q我们在创徏?Thread cȝ子类中重?run() ,加入U程所要执行的代码卛_。下面是一个例子:
public class MyThread extends Thread
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println
("创徏U程 " + number);
}
public void run() {
while(true) {
System.out.println
("U程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0;
i ?5; i++) new MyThread(i+1).start();
}
}
q种Ҏ单明了,W合大家的习惯,但是Q它也有一个很大的~点Q那是如果我们的类已经从一个类l承Q如程序必ȝ承自 Applet c)Q则无法再?Thread c,q时如果我们又不惛_立一个新的类Q应该怎么办呢Q?
我们不妨来探索一U新的方法:我们不创建Threadcȝ子类Q而是直接使用它,那么我们只能我们的Ҏ作ؓ参数传递给 Thread cȝ实例Q有点类似回调函数。但?Java 没有指针Q我们只能传递一个包含这个方法的cȝ实例?
那么如何限制q个cdd含这一Ҏ呢?当然是用接口!Q虽然抽象类也可满Q但是需要承,而我们之所以要采用q种新方法,不就是ؓ了避免承带来的限制吗?Q?
Java 提供了接?java.lang.Runnable 来支持这U方法?
Ҏ二:实现 Runnable 接口
Runnable接口只有一个方法run()Q我们声明自qcd现Runnable接口q提供这一ҎQ将我们的线E代码写入其中,完成了q一部分的Q务。但是Runnable接口q没有Q何对U程的支持,我们q必d建Threadcȝ实例Q这一炚w过Threadcȝ构造函数public Thread(Runnable target);来实现。下面是一个例子:
public class MyThread implements Runnable
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println("创徏U程 " + number);
}
public void run()
{
while(true)
{
System.out.println
("U程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0; i ?5;
i++) new Thread(new MyThread(i+1)).start();
}
}
严格地说Q创建Thread子类的实例也是可行的Q但是必L意的是,该子cdL有覆?Thread cȝ run ҎQ否则该U程执行的将是子cȝ run ҎQ而不是我们用以实现Runnable 接口的类?run ҎQ对此大家不妨试验一下?
使用 Runnable 接口来实现多U程使得我们能够在一个类中包Ҏ有的代码Q有利于装Q它的缺点在于,我们只能使用一套代码,若想创徏多个U程q各个U程执行不同的代码,则仍必须额外创徏c,如果q样的话Q在大多数情况下也许q不如直接用多个cd别?Thread 来得紧凑?
lg所qͼ两种Ҏ各有千秋Q大家可以灵z运用?
下面让我们一h研究一下多U程使用中的一些问题?
三、线E的四种状?
1. 新状态:U程已被创徏但尚未执行(start() 未被调用)?
2. 可执行状态:U程可以执行Q虽然不一定正在执行。CPU 旉随时可能被分配给该线E,从而得它执行?
3. M状态:正常情况?run() q回使得U程M。调?stop()?destroy() 亦有同样效果Q但是不被推荐,前者会产生异常Q后者是强制l止Q不会释N?
4. d状态:U程不会被分?CPU 旉Q无法执行?
四、线E的优先U?
U程的优先代表该线E的重要E度Q当有多个线E同时处于可执行状态ƈ{待获得 CPU 旉ӞU程调度pȝҎ各个U程的优先来决定给谁分?CPU 旉Q优先高的U程有更大的Z获得 CPU 旉Q优先低的U程也不是没有机会,只是Z要小一些Ş了?
你可以调?Thread cȝҎ getPriority() ?setPriority()来存取线E的优先U,U程的优先界于1(MIN_PRIORITY)?0(MAX_PRIORITY)之间Q缺省是5(NORM_PRIORITY)?
五、线E的同步
׃同一q程的多个线E共享同一片存储空_在带来方便的同时Q也带来了访问冲H这个严重的问题。Java语言提供了专门机制以解决q种冲突Q有效避免了同一个数据对象被多个U程同时讉K?
׃我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对Ҏ提出一套机Ӟq套机制是 synchronized 关键字,它包括两U用法:synchronized Ҏ?synchronized 块?
1. synchronized ҎQ通过在方法声明中加入 synchronized关键字来声明 synchronized Ҏ。如Q?
public synchronized void accessVal(int newVal);
synchronized Ҏ控制对类成员变量的访问:每个cd例对应一把锁Q每?synchronized Ҏ都必获得调用该Ҏ的类实例的锁方能执行Q否则所属线E阻塞,Ҏ一旦执行,q占该锁,直到从该Ҏq回时才锁释放Q此后被d的线E方能获得该锁,重新q入可执行状态?
q种机制保了同一时刻对于每一个类实例Q其所有声明ؓ synchronized 的成员函C臛_只有一个处于可执行状态(因ؓ臛_只有一个能够获得该cd例对应的锁)Q从而有效避免了cL员变量的讉K冲突Q只要所有可能访问类成员变量的方法均被声明ؓ synchronizedQ?
?Java 中,不光是类实例Q每一个类也对应一把锁Q这h们也可将cȝ静态成员函数声明ؓ synchronized Q以控制其对cȝ静态成员变量的讉K?
synchronized Ҏ的缺P若将一个大的方法声明ؓsynchronized 会大大影响效率Q典型地Q若线E类的方?run() 声明?synchronized Q由于在U程的整个生命期内它一直在q行Q因此将D它对本类M synchronized Ҏ的调用都永远不会成功。当然我们可以通过访问类成员变量的代码放C门的Ҏ中,其声明?synchronized Qƈ在主Ҏ中调用来解决q一问题Q但?Java 为我们提供了更好的解军_法,那就?synchronized 块?
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject)
{
//允许讉K控制的代?
}
synchronized 块是q样一个代码块Q其中的代码必须获得对象 syncObject Q如前所qͼ可以是类实例或类Q的锁方能执行,具体机制同前所q。由于可以针对Q意代码块Q且可Q意指定上锁的对象Q故灉|性较高?
六、线E的d
Z解决对共享存储区的访问冲H,Java 引入了同步机Ӟ现在让我们来考察多个U程对共享资源的讉KQ显然同步机制已l不够了Q因为在L时刻所要求的资源不一定已l准备好了被讉KQ反q来Q同一时刻准备好了的资源也可能不止一个。ؓ了解册U情况下的访问控刉题,Java 引入了对d机制的支持?
d指的是暂停一个线E的执行以等待某个条件发生(如某资源qAQ,学过操作pȝ的同学对它一定已l很熟悉了。Java 提供了大量方法来支持dQ下面让我们逐一分析?
1. sleep() ҎQsleep() 允许 指定以毫Uؓ单位的一D|间作为参敎ͼ它得线E在指定的时间内q入d状态,不能得到CPU 旉Q指定的旉一q,U程重新q入可执行状态。典型地Qsleep() 被用在等待某个资源就l的情ŞQ测试发现条件不满后,让线E阻塞一D|间后重新试Q直到条件满ؓ止?
2. suspend() ?resume() ҎQ两个方法配套用,suspend()使得U程q入d状态,q且不会自动恢复Q必d对应的resume() 被调用,才能使得U程重新q入可执行状态。典型地Qsuspend() ?resume() 被用在等待另一个线E生的l果的情形:试发现l果q没有生后Q让U程dQ另一个线E生了l果后,调用 resume() 使其恢复?
3. yield() ҎQyield() 使得U程攑ּ当前分得?CPU 旉Q但是不使线E阻塞,即线E仍处于可执行状态,随时可能再次分得 CPU 旉。调?yield() 的效果等价于调度E序认ؓ该线E已执行了够的旉从而{到另一个线E?
4. wait() ?notify() ҎQ两个方法配套用,wait() 使得U程q入d状态,它有两种形式Q一U允?指定以毫Uؓ单位的一D|间作为参敎ͼ另一U没有参敎ͼ前者当对应?notify() 被调用或者超出指定时间时U程重新q入可执行状态,后者则必须对应?notify() 被调用?
初看h它们?suspend() ?resume() ҎҎ有什么分别,但是事实上它们是截然不同的。区别的核心在于Q前面叙q的所有方法,d旉不会释放占用的锁Q如果占用了的话Q,而这一Ҏ法则相反?
上述的核心区别导致了一pd的细节上的区别?
首先Q前面叙q的所有方法都隶属?Thread c,但是q一对却直接隶属?Object c,也就是说Q所有对象都拥有q一Ҏ法。初看v来这十分不可思议Q但是实际上却是很自然的Q因一Ҏ法阻塞时要释攑֍用的锁,而锁是Q何对象都h的,调用L对象?wait() ҎDU程dQƈ且该对象上的锁被释放?
而调?L对象的notify()Ҏ则导致因调用该对象的 wait() Ҏ而阻塞的U程中随机选择的一个解除阻塞(但要{到获得锁后才真正可执行Q?
其次Q前面叙q的所有方法都可在M位置调用Q但是这一Ҏ法却必须?synchronized Ҏ或块中调用,理由也很单,只有在synchronized Ҏ或块中当前线E才占有锁,才有锁可以释放?
同样的道理,调用q一Ҏ法的对象上的锁必Mؓ当前U程所拥有Q这h有锁可以释放。因此,q一Ҏ法调用必L|在q样?synchronized Ҏ或块中,该方法或块的上锁对象是调用q一Ҏ法的对象。若不满一条gQ则E序虽然仍能~译Q但在运行时会出现IllegalMonitorStateException 异常?
wait() ?notify() Ҏ的上q特性决定了它们l常和synchronized Ҏ或块一起用,它们和操作pȝ的进E间通信机制作一个比较就会发现它们的怼性:synchronizedҎ或块提供了类g操作pȝ原语的功能,它们的执行不会受到多U程机制的干扎ͼ而这一Ҏ法则相当?block 和wakeup 原语Q这一Ҏ法均声明?synchronizedQ?
它们的结合得我们可以实现操作系l上一pd_֦的进E间通信的算法(如信号量法Q,q用于解军_U复杂的U程间通信问题。关?wait() ?notify() Ҏ最后再说明两点Q?
W一Q调?notify() ҎD解除d的线E是从因调用该对象的 wait() Ҏ而阻塞的U程中随机选取的,我们无法预料哪一个线E将会被选择Q所以编E时要特别小心,避免因这U不定性而生问题?
W二Q除?notify()Q还有一个方?notifyAll() 也可起到cM作用Q唯一的区别在于,调用 notifyAll() Ҏ把因调用该对象?wait() Ҏ而阻塞的所有线E一ơ性全部解除阻塞。当Ӟ只有获得锁的那一个线E才能进入可执行状态?
谈到dQ就不能不谈一谈死锁,略一分析p发现Qsuspend() Ҏ和不指定时期限?wait() Ҏ的调用都可能产生死锁。遗憄是,Java q不在语aU别上支持死锁的避免Q我们在~程中必d心地避免死锁?
以上我们?Java 中实现线E阻塞的各种Ҏ作了一番分析,我们重点分析?wait() ?notify()ҎQ因为它们的功能最强大Q用也最灉|Q但是这也导致了它们的效率较低,较容易出错。实际用中我们应该灉|使用各种ҎQ以便更好地辑ֈ我们的目的?
七、守护线E?
守护U程是一cȝD的U程Q它和普通线E的区别在于它ƈ不是应用E序的核心部分,当一个应用程序的所有非守护U程l止q行Ӟ即仍然有守护线E在q行Q应用程序也终止,反之Q只要有一个非守护U程在运行,应用E序׃会终止。守护线E一般被用于在后Cؓ其它U程提供服务?
可以通过调用Ҏ isDaemon() 来判断一个线E是否是守护U程Q也可以调用Ҏ setDaemon() 来将一个线E设为守护线E?
八、线E组
U程l是一?Java Ҏ的概念,?Java 中,U程l是cThreadGroup 的对象,每个U程都隶属于唯一一个线E组Q这个线E组在线E创建时指定q在U程的整个生命期内都不能更改?
你可以通过调用包含 ThreadGroup cd参数?Thread cL造函数来指定U程属的U程l,若没有指定,则线E缺省地隶属于名?system 的系l线E组?
?Java 中,除了预徏的系l线E组外,所有线E组都必L式创建。在 Java 中,除系l线E组外的每个U程l又隶属于另一个线E组Q你可以在创建线E组时指定其所隶属的线E组Q若没有指定Q则~省地隶属于pȝU程l。这P所有线E组l成了一以pȝU程lؓ根的树?
Java 允许我们对一个线E组中的所有线E同时进行操作,比如我们可以通过调用U程l的相应Ҏ来设|其中所有线E的优先U,也可以启动或d其中的所有线E?
Java 的线E组机制的另一个重要作用是U程安全。线E组机制允许我们通过分组来区分有不同安全Ҏ的U程Q对不同l的U程q行不同的处理,q可以通过U程l的分层l构来支持不对等安全措施的采用?
Java ?ThreadGroup cL供了大量的方法来方便我们对线E组树中的每一个线E组以及U程l中的每一个线E进行操作?
九、ȝ
在本文中Q我们讲qC Java 多线E编E的Ҏ面面Q包括创建线E,以及对多个线E进行调度、管理。我们深刻认识到了多U程~程的复杂性,以及U程切换开销带来的多U程E序的低效性,q也促我们认真地思考一个问题:我们是否需要多U程Q何旉要多U程Q?
多线E的核心在于多个代码块ƈ发执行,本质特点在于各代码块之间的代码是乱序执行的。我们的E序是否需要多U程Q就是要看这是否也是它的内在特点?
假如我们的程序根本不要求多个代码块ƈ发执行,那自然不需要用多U程Q假如我们的E序虽然要求多个代码块ƈ发执行,但是却不要求乱序Q则我们完全可以用一个@环来单高效地实现Q也不需要用多U程Q只有当它完全符合多U程的特ҎQ多U程机制对线E间通信和线E管理的强大支持才能有用武之圎ͼq时使用多线E才是值得的?
来自Q开发者在U?
另外如果你喜Ƣ电脑的话,我推荐你d学者之路看看~ ]]> java多线E?sleep()和wait()的区?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380941.htmlabin abin Sat, 16 Jun 2012 17:15:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380941.html http://www.aygfsteel.com/stevenjohn/comments/380941.html http://www.aygfsteel.com/stevenjohn/archive/2012/06/17/380941.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/380941.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/380941.html q两个方法主要来源是Qsleep用于U程控制Q而wait用于U程间的通信Q与wait配套的方法还有notify和notifyAll.
区别一Q?/p>
sleep是ThreadcȝҎQ是U程用来 控制自n程的,比如有一个要报时的线E,每一U中打印Z个时_那么我就需要在printҎ前面加上一个sleep让自己每隔一U执行一ơ。就像个闚w一栗?/p>
wait是ObjectcȝҎQ用来线E间的通信Q这个方法会使当前拥有该对象锁的q程{待知道其他U程调用notifyҎ时再醒来Q不q你也可以给他指定一个时_自动醒来。这个方法主要是用走不同U程之间的调度的?/p>
区别?Q?/p>
关于锁的释放 Q在q里假设大家已经知道了锁的概念及其意义。调用sleepҎ不会释放锁(自己的感觉是sleepҎ本来是和锁没有关系的,因ؓ他是一个线E用于管理自qҎQ不涉及U程通信Q?/p>
JDK 7 中的解释Q?/p>
“public static void sleep(long millis)
throws InterruptedException Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.The thread does not lose ownership of any monitors.
public final void wait() throws InterruptedException Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.“ 调用waitҎ会释攑ֽ前线E的锁(其实U程间的通信是靠对象来管理的Q所有操作一个对象的U程是这个对象通过自己的waitҎ来管理的Q就好像q个对象是电视机Q三个h是三个线E,那么电视机的遥控器就是这个锁Q假如现在A拿着遥控器,电视用waitҎQ那么A׃q遥控器,由jVM虚拟度,遥控器该交给谁。)【我惛_一个好玩的例子Q如果A拉K控器的期_他可以用自己的sleep每隔十分钟调一ơ电视台Q而在他调C息的十分钟期_遥控器还在他的手上~?/p>
区别三:
使用区域
׃wait函数的特D意义,所以他是应该放在同步语句块中的Q这h有意??/p>
注意Q两个方法都需要抛出异?/p>
个h见解Q有sleep和wait的第二个区别Q引起了我对JavaU程机制的一个疑问,目前q没有看qJDkq方面的源码Q其实看了,是木有看懂)Q线E的同步理Q是不是由对象在调度Q如果是对象在调度,那么JDK 1.5新引入的ReentrantLock机制比synchronized关键字更值得提倡。因Z更能反映么一个机制来。好多h不能理解wait和sleep的区别,我认为就是因为synchronized关键字的影响。当然自p不懂JAVA的线E具体实玎ͼ留作疑问以后有时间l研I吧
Java中的多线E是一U?strong>抢占式的机制 而不是分时机制。抢占式机制指的是有多个U程处于可运行状态,但是只有一个线E在q行?/span> 共同点: 1. 他们都是在多U程的环境下Q都可以在程序的调用处阻塞指定的毫秒敎ͼq返回?br /> 2. wait()和sleep()都可以通过interrupt()Ҏ打断U程的暂停状态,从而ɾU程立刻抛出InterruptedException?br /> 如果U程A希望立即l束U程BQ则可以对线EB对应的Thread实例调用interruptҎ。如果此ȝEB正在wait/sleep /joinQ则U程B会立L出InterruptedExceptionQ在catch() {} 中直接return卛_安全地结束线E?br /> 需要注意的是,InterruptedException是线E自׃内部抛出的,q不是interrupt()Ҏ抛出的。对某一U程调用 interrupt()Ӟ如果该线E正在执行普通的代码Q那么该U程Ҏ׃会抛出InterruptedException。但是,一旦该U程q入?wait()/sleep()/join()后,׃立刻抛出InterruptedException?br /> 不同点: 1. ThreadcȝҎQsleep(),yield(){?br /> Object的方法:wait()和notify(){?br /> 2. 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互Q来实现U程的同步?br /> sleepҎ没有释放锁,而waitҎ释放了锁Q得其他线E可以用同步控制块或者方法?br /> 3. waitQnotify和notifyAll只能在同步控制方法或者同步控制块里面使用Q而sleep可以在Q何地方?br />4. sleep必须捕获异常Q而waitQnotify和notifyAll不需要捕获异?nbsp;
U程的调? U程调度器按U程的优先高低选择高优先U程Q进入运行中状态)执行Q同时线E调度是抢先式调度,卛_果在当前U程执行q程中,一个更高优先的线E进入可q行状态,则这个线E立卌调度执行?
抢先式调度又分ؓQ时间片方式和独占方式。在旉片方式下Q当前活动线E执行完当前旉片后Q如果有其他处于qA状态的相同优先U的U程Q系l会执行权交给其他qA态的同优先U程Q当前活动线E{入等待执行队列,{待下一个时间片的调度? 在独占方式下Q当前活动线E一旦获得执行权Q将一直执行下去,直到执行完毕或由于某U原因主动放弃CPUQ或者是有一高优先的线E处于就l状态?/font>
]]> Java 多线E?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/06/06/380126.htmlabin abin Wed, 06 Jun 2012 06:19:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/06/06/380126.html http://www.aygfsteel.com/stevenjohn/comments/380126.html http://www.aygfsteel.com/stevenjohn/archive/2012/06/06/380126.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/380126.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/380126.html
sleep,wait,suspend,resume,join,interrupt,stop,destory
]]> q程和线E之间的区别和联p?/title> http://www.aygfsteel.com/stevenjohn/archive/2012/05/22/378842.htmlabin abin Tue, 22 May 2012 07:19:00 GMT http://www.aygfsteel.com/stevenjohn/archive/2012/05/22/378842.html http://www.aygfsteel.com/stevenjohn/comments/378842.html http://www.aygfsteel.com/stevenjohn/archive/2012/05/22/378842.html#Feedback 0 http://www.aygfsteel.com/stevenjohn/comments/commentRss/378842.html http://www.aygfsteel.com/stevenjohn/services/trackbacks/378842.html q程和程序区别和联系表现在以下方面:
1)E序只是一l指令的有序集合Q它本n没有Mq行的含义,它只?
一个静态的实体。而进E则不同Q它是程序在某个数据集上的执行?
q程是一个动态的实体Q它有自q生命周期。它因创生,?
调度而运行,因等待资源或事g而被处于{待状态,因完成Q务而被
撤消。反映了一个程序在一定的数据集上q行的全部动态过E?
2)q程和程序ƈ不是一一对应的,一个程序执行在不同的数据集上就?
Z同的q程Q可以用q程控制块来唯一地标识每个进E。而这一?
正是E序无法做到的,׃E序没有和数据生直接的联系Q既使是
执行不同的数据的E序Q他们的指o的集合依然是一LQ所以无?
唯一地标识出q些q行于不同数据集上的E序。一般来_一个进E?
肯定有一个与之对应的E序Q而且只有一个。而一个程序有可能没有
与之对应的进E?因ؓ它没有执?,也有可能有多个进E与之对?q?
行在几个不同的数据集??
3)q程q具有ƈ发性和交往性,q也与程序的闭性不同?
----------------------------------------------------------------------------------------------
q程和线E都是由操作pȝ所体会的程序运行的基本单元Q系l利用该基本单元实现pȝ对应用的q发性。进E和U程的区别在于:
而言?一个程序至有一个进E?一个进E至有一个线E?
U程的划分尺度小于进E,使得多线E程序的q发性高?
另外Q进E在执行q程中拥有独立的内存单元Q而多个线E共享内存,从而极大地提高了程序的q行效率?
U程在执行过E中与进E还是有区别的。每个独立的U程有一个程序运行的入口、顺序执行序列和E序的出口。但是线E不能够独立执行Q必M存在应用E序中,由应用程序提供多个线E执行控制?
从逻辑角度来看Q多U程的意义在于一个应用程序中Q有多个执行部分可以同时执行。但操作pȝq没有将多个U程看做多个独立的应用,来实现进E的调度和管理以及资源分配。这是q程和线E的重要区别?
q程是具有一定独立功能的E序关于某个数据集合上的一ơ运行活?q程是系l进行资源分配和调度的一个独立单?
U程是进E的一个实?是CPU调度和分z基本单位,它是比进E更的能独立运行的基本单位.U程自己基本上不拥有pȝ资源,只拥有一点在q行中必不可的资源(如程序计数器,一l寄存器和栈),但是它可与同属一个进E的其他的线E共享进E所拥有的全部资?
一个线E可以创建和撤销另一个线E?同一个进E中的多个线E之间可以ƈ发执?
----------------------------------------------------------------------------------------------
q程和线E的区别
说法一Q进E是h一定独立功能的E序关于某个数据集合上的一ơ运行活?q程是系l进行资源分配和调度的一个独立单?
U程是进E的一个实?是CPU调度和分z基本单位,它是比进E更的能独立运行的基本单位.U程自己基本上不拥有pȝ资源,只拥有一点在q行中必不可的资源(如程序计数器,一l寄存器和栈),但是它可与同属一个进E的其他的线E共享进E所拥有的全部资?
一个线E可以创建和撤销另一个线E?同一个进E中的多个线E之间可以ƈ发执?
说法二:q程和线E都是由操作pȝ所体会的程序运行的基本单元Q系l利用该基本单元实现pȝ对应用的q发性。进E和U程的区别在于:
而言?一个程序至有一个进E?一个进E至有一个线E?
U程的划分尺度小于进E,使得多线E程序的q发性高?
另外Q进E在执行q程中拥有独立的内存单元Q而多个线E共享内存,从而极大地提高了程序的q行效率?
U程在执行过E中与进E还是有区别的。每个独立的U程有一个程序运行的入口、顺序执行序列和E序的出口。但是线E不能够独立执行Q必M存在应用E序中,由应用程序提供多个线E执行控制?
从逻辑角度来看Q多U程的意义在于一个应用程序中Q有多个执行部分可以同时执行。但操作pȝq没有将多个U程看做多个独立的应用,来实现进E的调度和管理以及资源分配。这是q程和线E的重要区别?
说法三:多线E共存于应用E序中是C操作pȝ中的基本特征和重要标志。用qUNIX操作pȝ的读者知道进E,在UNIX操作pȝ中,每个应用E序的执行都在操作系l内怸登记一个进E标志,操作pȝҎ分配的标志对应用E序的执行进行调度和pȝ资源分配Q但q程和线E有什么区别呢Q?
q程和线E都是由操作pȝ所体会的程序运行的基本单元Q系l利用该基本单元实现pȝ对应用的q发性。进E和U程的区别在于:
U程的划分尺度小于进E,使得多线E程序的q发性搞?
另外Q进E在执行q程中拥有独立的内存单元Q而多个线E共享内存,从而极大地提高了程序的q行效率?
U程在执行过E中与进E还是有区别的。每个独立的U程有一个程序运行的入口、顺序执行序列和E序的出口。但是线E不能够独立执行Q必M存在应用E序中,由应用程序提供多个线E执行控制?
从逻辑角度来看Q多U程的意义在于一个应用程序中Q有多个执行部分可以同时执行。但操作pȝq没有将多个U程看做多个独立的应用,来实现进E的调度和管理以及资源分配。这是q程和线E的重要区别?
q程QProcessQ是最初定义在Unix{多用户、多d操作pȝ环境下用于表C应用程序在内存环境中基本执行单元的概念。以Unix操作pȝZQ进E是Unix操作pȝ环境中的基本成分、是pȝ资源分配的基本单位。Unix操作pȝ中完成的几乎所有用L理和资源分配{工作都是通过操作pȝ对应用程序进E的控制来实现的?
C、C++、Java{语a~写的源E序l相应的~译器编译成可执行文件后Q提交给计算机处理器q行。这Ӟ处在可执行状态中的应用程序称E。从用户角度来看Q进E是应用E序的一个执行过E。从操作pȝ核心角度来看Q进E代表的是操作系l分配的内存、CPU旉片等资源的基本单位,是ؓ正在q行的程序提供的q行环境。进E与应用E序的区别在于应用程序作Z个静态文件存储在计算机系l的盘{存储空间中Q而进E则是处于动态条件下由操作系l维护的pȝ资源理实体。多d环境下应用程序进E的主要特点包括Q?
●q程在执行过E中有内存单元的初始入口点,q且q程存活q程中始l拥有独立的内存地址I间Q?
●q程的生存期状态包括创建、就l、运行、阻塞和M{类型;
●从应用程序进E在执行q程中向CPU发出的运行指令Ş式不同,可以进E的状态分为用h和核心态。处于用h下的进E执行的是应用程序指令、处于核心态下的应用程序进E执行的是操作系l指令?
在Unix操作pȝ启动q程中,pȝ自动创徏swapper、init{系l进E,用于理内存资源以及对用戯E进行调度等。在Unix环境下无论是由操作系l创建的q程q要由应用程序执行创建的q程Q均拥有唯一的进E标识(PIDQ?
说法四:应用E序在执行过E中存在一个内存空间的初始入口点地址、一个程序执行过E中的代码执行序列以及用于标识进E结束的内存出口点地址Q在q程执行q程中的每一旉点均有唯一的处理器指o与内存单元地址相对应?
Java语言中定义的U程QThreadQ同样包括一个内存入口点地址、一个出口点地址以及能够序执行的代码序列。但是进E与U程的重要区别在于线E不能够单独执行Q它必须q行在处于活动状态的应用E序q程中,因此可以定义U程是程序内部的hq发性的序代码?
Unix操作pȝ和Microsoft Windows操作pȝ支持多用戗多q程的ƈ发执行,而Java语言支持应用E序q程内部的多个执行线E的q发执行。多U程的意义在于一个应用程序的多个逻辑单元可以q发地执行。但是多U程q不意味着多个用户q程在执行,操作pȝ也不把每个线E作为独立的q程来分配独立的pȝ资源。进E可以创建其子进E,子进E与父进E拥有不同的可执行代码和数据内存I间。而在用于代表应用E序的进E中多个U程׃n数据内存I间Q但保持每个U程拥有独立的执行堆栈和E序执行上下文(ContextQ?
Z上述区别Q线E也可以UCؓdq程 (Light Weight ProcessQLWP)。不同线E间允许d协作和数据交换,使得在计机pȝ资源消耗等斚w非常廉h?
U程需要操作系l的支持Q不是所有类型的计算机都支持多线E应用程序。JavaE序设计语言线E支持与语言q行环境l合在一P提供了多dq发执行的能力。这好比一个h在处理家务的q程中,衣服放到洗衣机中自动洗涤后大cx在电饭锅里,然后开始做菜。等菜做好了Q饭熟了同时衣服也洗好了?
需要注意的是:在应用程序中使用多线E不会增?CPU 的数据处理能力。只有在多CPU 的计机或者在|络计算体系l构下,JavaE序划分为多个ƈ发执行线E后Q同时启动多个线E运行,使不同的U程q行在基于不同处理器的Java虚拟ZQ才能提高应用程序的执行效率?
]]>
վ֩ģ壺
|
|
ɽ |
ʹ |
|
|
|
|
۽ |
|
|
Ī |
ɽ |
|
鴨 |
ͨ |
|
|
|
ᶫ |
|
Ѩ |
|
ĺ |
|
Ԫ |
踽 |
ɽ |
ֺ |
|
ƽ |
|
ν |
|
ϼ |
|
ƽ |
̨ |
|
ƽ |
Ϫ |