我按照各位大侠的意见做了修改如下 package testthread; /** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author unascribed * @version 1.0 */ class FinalCount{ public static int y=1; public static synchronized void countCreate1(){ for(int i=0;i<5;i++){ System.out.println(FinalCount.y); ++FinalCount.y; } } public static synchronized void countCreate(){ for(int i=0;i<5;i++){ System.out.println(FinalCount.y); --FinalCount.y; } }} class Thread1 extends Thread{ public void run(){ FinalCount.countCreate1(); } } class Thread2 extends Thread{ public void run(){ FinalCount.countCreate(); } } public class TestThread { public static void main(String[] args){ System.out.println(FinalCount.y); Thread1 thread1a=new Thread1(); Thread1 thread1b=new Thread1(); Thread2 thread2a=new Thread2(); Thread2 thread2b=new Thread2(); thread1a.start(); thread1b.start(); thread2a.start(); thread2b.start(); }} 可惜输出如下: 112345678910111098765432看来各位大侠还要劳神一下?谢谢!!!
to ajiao: 这不关并发访问的事,所以同步不同步无所谓。 其实问题出在楼主对线程的运行不太理解。 他希望程序按 thread1a,thread1b,thread2a,thread2b 这样的顺序运行。 其实这是很不可靠的。多线程程序的运行顺序是不可预测的。 这个程序的结果看上去应该更怪,因为线程中的循环很小,在一个时间片 中就可完成。循环放大到一个时间片不能完成时,结果会更怪。
class FinalCount{ public static int y=1; public static int addCnt=0; public static int subCnt=0; public static int expectedCnt=10; public static synchronized void countCreate1(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName());//add watch //if(i==0){ System.out.println(y); //} ++y;//改 addCnt++; if(addCnt==expectedCnt){//print the last value System.out.println("the last add result,gosh---->"); System.out.println(y); } } } public static synchronized void countCreate(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName());//add watch //System.out.println(FinalCount.y);//你为什么要放在这那?你要想打印1么?呵呵 --y;//改! System.out.println(y); } }} class Thread1 extends Thread{ public Thread1(String name){//add name super(name); } public void run(){ FinalCount.countCreate1(); } } class Thread2 extends Thread{ public Thread2(String name){//add name super(name); } public void run(){ FinalCount.countCreate(); } } public class TestThread { public static void main(String[] args){ //System.out.println(FinalCount.y);//这条语句极其好啊,让我极其恼火,呵呵 Thread1 thread1a=new Thread1("thread1a"); Thread1 thread1b=new Thread1("thread1b"); Thread2 thread2a=new Thread2("thread2a"); Thread2 thread2b=new Thread2("thread2b"); thread1a.start(); thread1b.start(); thread2a.start(); thread2b.start(); }}老弟啊,你的算法,甚至可以说想法有些不妥吧,呵呵,让我改起来很恼火哦,另外,你的线程认知不够哦,多多努力.............
package testthread;class FinalCount{ public static int y=1; public static int addCnt=0; public static int subCnt=0; public static int expectedCnt=10; public static synchronized void countCreate1(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName());//add watch //if(i==0){ System.out.println(y); //} ++y;//改 addCnt++; if(addCnt==expectedCnt){//print the last value System.out.println("the last add result,gosh---->"); System.out.println(y); } } } public static synchronized void countCreate(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName());//add watch --y; System.out.println(y); } }} class Thread1 extends Thread{ public Thread1(String name){//add name super(name); } public void run(){ FinalCount.countCreate1(); } } class Thread2 extends Thread{ public Thread2(String name){//add name super(name); } public void run(){ FinalCount.countCreate(); } } public class TestThread { public static void main(String[] args){ Thread1 thread1a=new Thread1("thread1a"); Thread1 thread1b=new Thread1("thread1b"); Thread2 thread2a=new Thread2("thread2a"); Thread2 thread2b=new Thread2("thread2b"); thread1a.start(); thread1a.setPriority(10); thread1b.start(); thread1b.setPriority(8); thread2a.start(); thread2b.start(); thread2b.setPriority(3); }} 结果如下 thread1a1thread1a2thread1a3thread1a4thread1a5thread1b6thread1b7thread1b8thread1b9thread1b10the last add result,gosh---->11thread2a10thread2a9thread2a8thread2a7thread2a6thread2b5thread2b4thread2b3thread2b2thread2b1遵照各位大哥的意见,我作如上修改,,是希望输出。我的想法是这样的,不知对不对 1:用同步控制对y的访问,这样他属于同一线程,别的线程不能访问他,这样他能递增。 2:用线程优先极控制程序执行。 不知以上对不对,请各位大哥指正,也好快快结贴,谢谢!!!
那么多位大哥给你提了醒,你还是没能够领悟,呵呵,需要好好看看书哦 1.synchronized同步的作用是,保证任何时间,只有一个线程能访问同步对象中被synchronized的方法。这样做的目的在于,当多个线程要对同一资源做出修改或者读取时(比如你这里的y),只有一个时间只有一个线程在能够访问这些同步方法。这样做是为了保证数据操作的原子性,原子性的意思就是,当我要操作这个数据时,虽然可能有几个步骤,但是在这些步骤当中,我的操作必须保证连贯,期间不被其他人(这里指其他线程)打扰。因而我们使用synchronized来对数据敏感方法全部保护起来,来保证操作的安全性。2.线程优先级是可以设定的,但是只能从概率上对线程的执行进行了分配。比如a线程是最大优先级别,b线程级别较低,在一个较长的时间范围内,可以保证a的执行次数要多于b。但是在任何一个时间点,谁被虚拟机调用却不是固定的。因而,你这个程序不能说能够完全确保你所要达到的输出,因为各个线程执行的先后是不固定的,这里1a与1b只是说执行任务时间短,在2a与2b启动时已经完成了run中的执行体,对于2a与2b之间,为什么能够显示2a完之后才到2b,就是因为这个原因,因为线程在启动后很快死亡,在这期间不存在争抢。3.为了让你得到感性与理性的认识,这里你运行我提供的例子:public class ReadDirtyTest{ public static void main(String[] args){ ReadWrite rw=new ReadDirtyTestThreadSafe(); new WriteThread(rw).start(); new ReadThread(rw).start(); }}interface ReadWrite{ public void addReadMe(); public void readReadMe(); public int getReadMe(); //public void reSetReadMe(); }//public class ReadDirtyTest{ class ReadDirtyTestThreadSafe implements ReadWrite{ private int readMe;
/*public static void main(String[] args){ ReadDirtyTest test=new ReadDirtyTest(); new WriteThread(test).start();//´´½¨²¢Æô¶¯Ð´Ïß³Ì new ReadThread(test).start();//´´½¨²¢Æô¶¯¶ÁÏß³Ì }*/
synchronized public void addReadMe(){ //ÿ´Îadd²Ù×÷¶ÔreadmeÖ´ÐÐÁ½´ÎÀÛ¼Ó, System.out.println("Trans1:begin adding readme value=============================="); //µÚÒ»´ÎÀÛ¼Ó readMe++; //´òÓ¡µÚÒ»´ÎÀÛ¼ÓºóµÄÁÙʱֵ System.out.println("the temporary readme value now is " + readMe); try{ //ʹµ±Ç°Ð´Ïß³ÌÐÝÃß,¸ø¶ÁÏß³ÌÌÚ³öÔËÐÐʱ¼ä Thread.currentThread().sleep(1000); }catch(InterruptedException x){ System.out.println("InterruptedException is thrown out..."); } //µÚ¶þ´ÎÀÛ¼Ó readMe++; //´òÓ¡×îÖÕÐ޸ĺóµÄÖµ System.out.println("the expected readme value now is " + readMe); System.out.println("Trans2:finish adding readme value==============================");
public class Driver { public static volatile int j=1; public static void main(String[] args){ IncrThread it1=new IncrThread(); IncrThread it2=new IncrThread(); DecrThread dt1=new DecrThread(); DecrThread dt2=new DecrThread(); it1.start(); it2.start(); dt1.start(); dt2.start(); } class IncrementThread extends Thread{ public void run(){ for(int i=0;i<5;i++){ System.out.println(j++); } } } class DecrementThread extends Thread{ public void run(){ for(int i=0;i<5;i++){ System.out.println(--j); } } } }
the posted program gives you exactly what you want. but you have to know that it's not reliable. as a warning, when doing multi-threading programming, don't trust the thread scheduler. if you want more details about threading and how JVM scheduler works, i recommamd that you read the JVM specification (you can download a free copy from sun's website). last but not the least, don't predict the sequence in which your threads will run, it's totally unpredictable.
To tiger999: 大哥的例子小弟在jbuilder7下不能运行,提示为: 'this' can not be referenced from a static context at line 10. (已经修改了不匹配的类名:DecrementThread->DecrThread.IncrementThread-> IncrThread)????
喂喂,看不下去了,这么简单的问题,讨论这么久, 搂主的主要问题在于没有对要操作的数据设置排它锁,笨 以下程序就可以完成你的要求了,看吧 /** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author unascribed * @version 1.0 */ class FinalCount{ public static int y=1; public static synchronized void increase(){ y++; } public static synchronized void decrease(){ y--; } } class Thread1 extends Thread{ public void run(){ for(int i=0;i<5;i++){ FinalCount.increase(); System.out.println(FinalCount.y); } } } class Thread2 extends Thread{ public void run(){ for(int i=0;i<5;i++){ FinalCount.decrease(); System.out.println(FinalCount.y); } } } public class test { public static void main(String[] args){ System.out.println(FinalCount.y); Thread1 thread1a=new Thread1(); Thread1 thread1b=new Thread1(); Thread2 thread2a=new Thread2(); Thread2 thread2b=new Thread2(); thread1a.start(); thread1b.start(); thread2a.start(); thread2b.start(); }} 输出结果为: 1 2 3 4 5 6 7 8 9 10 11 10 9 8 7 6 5 4 3 2 1这样行了吧?
今天仔细看了aJiao老弟的说法,发现了极大的错误ajiao said: 1.根本就不需要设置线程优先权,前两个线程肯定是优于后两个。 2.运行的顺序肯定是按他们定义的先后顺序。 3.因为这四个线程的run函数都是访问类FinalCount的synchronized函数, 类FinalCount的机锁同时只能有一个线程访问,当第一个线程thread1a在运行时, 其它的3个线程由于不拥有类FinalCount的机锁,因此只能等待。 (即使在第一个线程里循环1万次,或者sleep(1000),cpu也不会把运行权交给其它公用一个机锁的线程,除非你调用了对象的wait())问题1存在的问题是,“前两个线程肯定是优于后两个”,它们是被最先start,肯定是被优先“考虑”执行的,但是并不代表它们优先级别高,我前面说过,优先级不是先后的问题,而是在一个时间范围内被执行多少的概率问题。问题2存在的问题是,前面1提到“肯定是被优先“考虑”执行的”,仅仅是“优先考虑”,而不是说一定是这个顺序。问题3在表达上面存在模糊之处,含糊的地方是“即使在第一个线程里循环1万次”,不应该说在线程里循环,应该是在FinalCount类方法中CountCreate里头循环一万次这种说法才确切(如果按照你这种改法的话--就是把for循环放到FinalCount的CountCreate里头),在CountCreate里无论循环多少次还是sleep,只要没有走出这个被synchronized的方法体,机锁是不会被释放的。为了形象一些,可以对程序做出这样的改动:#######运行更改一: public static synchronized void countCreate(){ try{ System.out.println("I will sleep...."); Thread.currentThread().sleep(1000); }catch(Exception x){ } for(int i=0;i<5;i++){ System.out.println(FinalCount.y); --FinalCount.y; } } 结果是: 1 2 3 4 5 6 7 8 9 10 I will sleep.... 11 10 9 8 7 I will sleep.... 6 5 4 3 2 #######运行更改二: class Thread1 extends Thread{ public void run(){ try{ System.out.println("i will sleep..."); sleep(50); }catch(Exception x){ } FinalCount.countCreate1(); } }结果: i will sleep... i will sleep... 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -8 -7 -6 -5 -4 -3 -2 -1 0最后应该指出的是,诚然如 tiger999(不吃肉的老虎) 所说,是因为楼主老弟对线程的理解还不够准确和深刻,将for循环放入synchronized中并非一个灵活而且正确的解决方式,我将给出一个解决方案,如下帖。
在提出我的解决方法前,先看看redsnakecao(曹) 的解法,如果,我们在main方法中稍微做一下调整,来看看会有什么结果:public class test { public static void main(String[] args){ System.out.println(FinalCount.y); Thread1 thread1a=new Thread1(); Thread1 thread1b=new Thread1(); Thread2 thread2a=new Thread2(); Thread2 thread2b=new Thread2(); thread2a.start();//这里将decrease 线程提前 thread1a.start(); thread1b.start();
thread2b.start(); }}运行结果是: 1 0 -1 -2 -3 -4 -3 -2 -1 0 1 2 3 4 5 6 5 4 3 2 1这种改法是很极端的改法,就是模拟了一种状态,两个加线程被block住(因为jvm的原因,几率虽然很小),thread2a被率先执行的这么一种情况。另外也可以这样改: class Thread1 extends Thread{ public void run(){ try{ System.out.println("Sorry, I am blocked by unknown reason,damn JVM, sun can not ensure it..."); sleep(50);
private int maxValue=10;//default max value private int minValue=1;//default min value
private boolean releaseIncThreadFlag=false;//release flag for decrease thread private boolean releaseDecThreadFlag=false;//release flag for increase thread
private boolean arriveMax=false;
public FinalCount(){
}
public FinalCount(int max,int min){ //if it is valid max-min releationship, override the default scenary if(max>min){ maxValue=max; minValue=min; y=min; } } public synchronized void increase(){ //limitation control if(y==maxValue) return; printY(); y++; //increase to the max value, sets the control parameters and //notify all waiting threads if(y==maxValue){ releaseIncThreadFlag=true; arriveMax=true; printY();//print the top value notifyAll(); } } public synchronized void decrease(){ //limitation control if(y==minValue) return; y--; printY(); //decrease to the min value, sets the control parameters and //notify all waiting threads if(y==minValue){ releaseDecThreadFlag=true; arriveMax=false; notifyAll(); } }
private void printY(){ System.out.println("thread name=" + Thread.currentThread().getName()); System.out.println(y); } //wait() control method public synchronized boolean isArriveMaxValue(){ return arriveMax; } //wait() control method public synchronized boolean isReleaseIncThread(){ return releaseIncThreadFlag; } //wait() control method public synchronized boolean isReleaseDecThread(){ return releaseDecThreadFlag; } //get the max value for loop count public int getMaxValue(){ return maxValue; } } class IncThread extends Thread{ FinalCount count;
public IncThread(String name,FinalCount count){ super(name); this.count=count; }
} } } //if need to release current thread if(count.isReleaseIncThread()) break; count.increase();
}
//release prompt: System.out.println("====== Thread(" + getName() + ") is released....");
} } class DecThread extends Thread{ FinalCount count;
public DecThread(String name,FinalCount count){ super(name); this.count=count; }
public void run(){
for(int i=0;i<count.getMaxValue();i++){ synchronized(count){ //when still not arrive at the max value,or still not release, waiting... while(!count.isArriveMaxValue() & !count.isReleaseDecThread()){ try{ count.wait(); }catch(Exception x){
incThread3.start(); decThread1.start(); }}运行结果: ===============================thread name=incThread2 1 thread name=incThread2 2 thread name=incThread2 3 thread name=incThread2 4 thread name=incThread1 5 thread name=incThread4 6 thread name=incThread3 7 thread name=incThread1 8 thread name=incThread4 9 thread name=incThread4 10 ====== Thread(incThread3) is released.... thread name=decThread2 9 thread name=decThread3 8 thread name=decThread1 7 ====== Thread(incThread4) is released.... ====== Thread(incThread2) is released.... thread name=decThread2 ====== Thread(incThread1) is released.... 6 thread name=decThread3 5 thread name=decThread1 4 thread name=decThread1 3 thread name=decThread2 2 thread name=decThread1 1 ====== Thread(decThread1) is released.... ====== Thread(decThread2) is released.... ====== Thread(decThread3) is released....====================================== 这个解决方案更显得灵活,也能够完全确保数值由1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1这种顺序输出,而不论加减线程启动的先后,也可以将阈值设定在非1,10的任一一个范围,消除了不确定性,也充分利用了java提供的线程控制机制。如,可以这样改: main函数中: FinalCount fc=new FinalCount(13,12); ... 运行结果: thread name=incThread2 12 thread name=incThread2 13 thread name=decThread2 12 ====== Thread(decThread2) is released.... ====== Thread(decThread3) is released.... ====== Thread(incThread2) is released.... ====== Thread(incThread1) is released.... ====== Thread(incThread4) is released.... ====== Thread(incThread3) is released.... ====== Thread(decThread1) is released.... 这个例子是使用java线程的一个非常好的范例,也是我为什么在上边的帖子中提到说这个问题精彩的原因所在。
下面的程序应该是可靠的,你可任意调换线程起动次序,结果都一样。public class Test { public static void main(String[] args){ SharedData sd=new SharedData(); IncrementThread it1=new IncrementThread(sd); IncrementThread it2=new IncrementThread(sd); DecrementThread dt1=new DecrementThread(sd); DecrementThread dt2=new DecrementThread(sd); dt1.start(); it1.start(); dt2.start(); it2.start(); } } class IncrementThread extends Thread{ private SharedData sd=null; public IncrementThread(SharedData sd){ this.sd=sd; } public void run(){ for(int i=0;i<500;i++){ if(sd.whosRun==sd.INCREMENT_RUN) System.out.println(sd.j++); if(sd.j==1001){ sd.whosRun=sd.DECRMENT_RUN; } } } } class DecrementThread extends Thread{ private SharedData sd=null; public DecrementThread(SharedData sd){ this.sd = sd; } public void run(){ synchronized(sd){ while(sd.whosRun!=sd.DECRMENT_RUN){ try{ sd.wait(); }catch(Exception e){} } for(int i=0;i<500;i++){ System.out.println(--sd.j); } } }}class SharedData extends Thread{ public int j=1; public final int INCREMENT_RUN=0; public final int DECRMENT_RUN=1; public volatile int whosRun=0; public boolean running=true; public SharedData(){ this.setDaemon(true); } public void run(){ while(true){ if(whosRun==INCREMENT_RUN) notifyAll(); } } }
To tiger999(不吃肉的老虎)大哥: 我运行你的程序,得出结果如下,只有递增过程,无递减。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
class Thread1 extends Thread{
private synchronized void countCreate()class Thread2 extends Thread
private synchronized void countCreate()
你这两个类中两个countCreate函数分别是对应了两个对象的机锁(一个是Thread1对象,一个是Thread2对象拥有的 ),根本就没法实现你的需求改正:把synchronized countCreate函数作为类FinalCount的成员函数,Thread1和Thread2
的run中再调用countCreate
package testthread;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author unascribed
* @version 1.0
*/
class FinalCount{
public static int y=1;
public static synchronized void countCreate1(){
for(int i=0;i<5;i++){
System.out.println(FinalCount.y);
++FinalCount.y;
}
}
public static synchronized void countCreate(){
for(int i=0;i<5;i++){
System.out.println(FinalCount.y);
--FinalCount.y;
}
}}
class Thread1 extends Thread{ public void run(){
FinalCount.countCreate1();
}
}
class Thread2 extends Thread{ public void run(){
FinalCount.countCreate();
}
}
public class TestThread {
public static void main(String[] args){
System.out.println(FinalCount.y);
Thread1 thread1a=new Thread1();
Thread1 thread1b=new Thread1();
Thread2 thread2a=new Thread2();
Thread2 thread2b=new Thread2();
thread1a.start();
thread1b.start();
thread2a.start();
thread2b.start();
}}
可惜输出如下:
112345678910111098765432看来各位大侠还要劳神一下?谢谢!!!
这不关并发访问的事,所以同步不同步无所谓。
其实问题出在楼主对线程的运行不太理解。
他希望程序按 thread1a,thread1b,thread2a,thread2b 这样的顺序运行。
其实这是很不可靠的。多线程程序的运行顺序是不可预测的。
这个程序的结果看上去应该更怪,因为线程中的循环很小,在一个时间片
中就可完成。循环放大到一个时间片不能完成时,结果会更怪。
public static int y=1;
public static int addCnt=0;
public static int subCnt=0;
public static int expectedCnt=10;
public static synchronized void countCreate1(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName());//add watch
//if(i==0){
System.out.println(y);
//}
++y;//改
addCnt++;
if(addCnt==expectedCnt){//print the last value
System.out.println("the last add result,gosh---->");
System.out.println(y);
}
}
}
public static synchronized void countCreate(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName());//add watch
//System.out.println(FinalCount.y);//你为什么要放在这那?你要想打印1么?呵呵
--y;//改!
System.out.println(y);
}
}}
class Thread1 extends Thread{
public Thread1(String name){//add name
super(name);
}
public void run(){
FinalCount.countCreate1();
}
}
class Thread2 extends Thread{
public Thread2(String name){//add name
super(name);
}
public void run(){
FinalCount.countCreate();
}
}
public class TestThread {
public static void main(String[] args){
//System.out.println(FinalCount.y);//这条语句极其好啊,让我极其恼火,呵呵
Thread1 thread1a=new Thread1("thread1a");
Thread1 thread1b=new Thread1("thread1b");
Thread2 thread2a=new Thread2("thread2a");
Thread2 thread2b=new Thread2("thread2b");
thread1a.start();
thread1b.start();
thread2a.start();
thread2b.start();
}}老弟啊,你的算法,甚至可以说想法有些不妥吧,呵呵,让我改起来很恼火哦,另外,你的线程认知不够哦,多多努力.............
public static int y=1;
public static int addCnt=0;
public static int subCnt=0;
public static int expectedCnt=10;
public static synchronized void countCreate1(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName());//add watch
//if(i==0){
System.out.println(y);
//}
++y;//改
addCnt++;
if(addCnt==expectedCnt){//print the last value
System.out.println("the last add result,gosh---->");
System.out.println(y);
}
}
}
public static synchronized void countCreate(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName());//add watch
--y;
System.out.println(y);
}
}}
class Thread1 extends Thread{
public Thread1(String name){//add name
super(name);
}
public void run(){
FinalCount.countCreate1();
}
}
class Thread2 extends Thread{
public Thread2(String name){//add name
super(name);
}
public void run(){
FinalCount.countCreate();
}
}
public class TestThread {
public static void main(String[] args){
Thread1 thread1a=new Thread1("thread1a");
Thread1 thread1b=new Thread1("thread1b");
Thread2 thread2a=new Thread2("thread2a");
Thread2 thread2b=new Thread2("thread2b");
thread1a.start();
thread1a.setPriority(10);
thread1b.start();
thread1b.setPriority(8);
thread2a.start();
thread2b.start();
thread2b.setPriority(3);
}}
结果如下
thread1a1thread1a2thread1a3thread1a4thread1a5thread1b6thread1b7thread1b8thread1b9thread1b10the last add result,gosh---->11thread2a10thread2a9thread2a8thread2a7thread2a6thread2b5thread2b4thread2b3thread2b2thread2b1遵照各位大哥的意见,我作如上修改,,是希望输出。我的想法是这样的,不知对不对
1:用同步控制对y的访问,这样他属于同一线程,别的线程不能访问他,这样他能递增。
2:用线程优先极控制程序执行。
不知以上对不对,请各位大哥指正,也好快快结贴,谢谢!!!
1.synchronized同步的作用是,保证任何时间,只有一个线程能访问同步对象中被synchronized的方法。这样做的目的在于,当多个线程要对同一资源做出修改或者读取时(比如你这里的y),只有一个时间只有一个线程在能够访问这些同步方法。这样做是为了保证数据操作的原子性,原子性的意思就是,当我要操作这个数据时,虽然可能有几个步骤,但是在这些步骤当中,我的操作必须保证连贯,期间不被其他人(这里指其他线程)打扰。因而我们使用synchronized来对数据敏感方法全部保护起来,来保证操作的安全性。2.线程优先级是可以设定的,但是只能从概率上对线程的执行进行了分配。比如a线程是最大优先级别,b线程级别较低,在一个较长的时间范围内,可以保证a的执行次数要多于b。但是在任何一个时间点,谁被虚拟机调用却不是固定的。因而,你这个程序不能说能够完全确保你所要达到的输出,因为各个线程执行的先后是不固定的,这里1a与1b只是说执行任务时间短,在2a与2b启动时已经完成了run中的执行体,对于2a与2b之间,为什么能够显示2a完之后才到2b,就是因为这个原因,因为线程在启动后很快死亡,在这期间不存在争抢。3.为了让你得到感性与理性的认识,这里你运行我提供的例子:public class ReadDirtyTest{
public static void main(String[] args){
ReadWrite rw=new ReadDirtyTestThreadSafe();
new WriteThread(rw).start();
new ReadThread(rw).start();
}}interface ReadWrite{
public void addReadMe();
public void readReadMe();
public int getReadMe();
//public void reSetReadMe();
}//public class ReadDirtyTest{
class ReadDirtyTestThreadSafe implements ReadWrite{
private int readMe;
/*public static void main(String[] args){
ReadDirtyTest test=new ReadDirtyTest();
new WriteThread(test).start();//´´½¨²¢Æô¶¯Ð´Ïß³Ì
new ReadThread(test).start();//´´½¨²¢Æô¶¯¶ÁÏß³Ì
}*/
synchronized public void addReadMe(){
//ÿ´Îadd²Ù×÷¶ÔreadmeÖ´ÐÐÁ½´ÎÀÛ¼Ó,
System.out.println("Trans1:begin adding readme value==============================");
//µÚÒ»´ÎÀÛ¼Ó
readMe++;
//´òÓ¡µÚÒ»´ÎÀÛ¼ÓºóµÄÁÙʱֵ
System.out.println("the temporary readme value now is " + readMe);
try{
//ʹµ±Ç°Ð´Ïß³ÌÐÝÃß,¸ø¶ÁÏß³ÌÌÚ³öÔËÐÐʱ¼ä
Thread.currentThread().sleep(1000);
}catch(InterruptedException x){
System.out.println("InterruptedException is thrown out...");
}
//µÚ¶þ´ÎÀÛ¼Ó
readMe++;
//´òÓ¡×îÖÕÐ޸ĺóµÄÖµ
System.out.println("the expected readme value now is " + readMe);
System.out.println("Trans2:finish adding readme value==============================");
}
synchronized public void readReadMe(){
//¶Áµ±Ç°readmeµÄÖµ,ÓпÉÄܶÁ³öµÄÊÇaddReadMe²úÉúµÄdirtyÖµ
System.out.println("read readme vlaue=" + readMe + "***Maybe Dirty Read***");
try{
Thread.currentThread().sleep(50);
}catch(InterruptedException x){
System.out.println("InterruptedException is thrown out...");
}
}
synchronized public int getReadMe(){
return readMe;
}
}class WriteThread extends Thread{
//ReadDirtyTest test;
ReadWrite test;
//public WriteThread(ReadDirtyTest test){
public WriteThread(ReadWrite test){
super("WriteThread");
this.test=test;
}
public void run(){
//while(test.readMe<5){
while(test.getReadMe()<5){
test.addReadMe();
}
}
}class ReadThread extends Thread{
//ReadDirtyTest test;
ReadWrite test;
//public ReadThread(ReadDirtyTest test){
public ReadThread(ReadWrite test){
super("ReadThread");
this.test=test;
}
public void run(){
//while(test.readMe<5){
while(test.getReadMe()<5){
test.readReadMe();
}
}
}这是正确的程序,当你把标有synchronized的方法去掉synchronized标识后,再运行一遍看看,思考一遍,你会有收益的。
可是如何实现如下目标,i初始值为1,用前两个线程使i递增,后两个线程使i递减,输出i的值如下:1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1,这是我在一家中国目前排名前5的一家软件公司应聘的题目。这样看来似乎无解,因为不能百分之百的使前两个线程快于后两个线程,郁闷啊!!!
运行的顺序肯定是按他们定义的先后顺序。
因为这四个线程的run函数都是访问类FinalCount的synchronized函数,
类FinalCount的机锁同时只能有一个线程访问,当第一个线程thread1a在运行时,
其它的3个线程由于不拥有类FinalCount的机锁,因此只能等待。
(即使在第一个线程里循环1万次,或者sleep(1000),cpu也不会把运行权交给其它公用一个机锁的线程,除非你调用了对象的wait())
里面加入一个判断,当y被加到10的时候,就停止。相应的在countCreate()中加入一个判断,
防止y被减成0
public static synchronized void countCreate1(){
for(int i=0;i<5;i++){
if(y==10)
System.out.println(y);
else
System.out.println(y++);
} }public static synchronized void countCreate(){
for(int i=0;i<5;i++){
System.out.println(y);
if(y!=1)
--y;
}
}
这个到不一定,你说得锁定,只是在同一线程的内部运行的时候,从一个线程到另一线程时候,比如线程一用完,可能线程三开始运行,而不是线程2,所以结果有时会是:
1 2 3 4 5 6 5 4 3 2 1 0 -1 -2 -3 -4 -3 -2 -1 -0 1
这个结果有时换一台电脑一下就出来,试一试就知道。我就运行出来过,大哥也可以试一试,jxspace说得没错。可能这个问题是不是要换一种思路???
另外,最正确也是最合理的方式是采用信号量来实现,但现在太晚了,明天我来将其实现,呵呵,好题目,精彩啊。
public class Driver { public static volatile int j=1; public static void main(String[] args){
IncrThread it1=new IncrThread();
IncrThread it2=new IncrThread();
DecrThread dt1=new DecrThread();
DecrThread dt2=new DecrThread();
it1.start();
it2.start();
dt1.start();
dt2.start(); } class IncrementThread extends Thread{
public void run(){
for(int i=0;i<5;i++){
System.out.println(j++);
}
}
} class DecrementThread extends Thread{
public void run(){
for(int i=0;i<5;i++){
System.out.println(--j);
}
}
}
}
trust the thread scheduler. if you want more details about threading and how JVM
scheduler works, i recommamd that you read the JVM specification (you can download a free copy from sun's website). last but not the least, don't predict
the sequence in which your threads will run, it's totally unpredictable.
大哥的例子小弟在jbuilder7下不能运行,提示为:
'this' can not be referenced from a static context at line 10.
(已经修改了不匹配的类名:DecrementThread->DecrThread.IncrementThread->
IncrThread)????
搂主的主要问题在于没有对要操作的数据设置排它锁,笨
以下程序就可以完成你的要求了,看吧
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author unascribed
* @version 1.0
*/
class FinalCount{
public static int y=1;
public static synchronized void increase(){
y++;
}
public static synchronized void decrease(){
y--;
}
}
class Thread1 extends Thread{
public void run(){
for(int i=0;i<5;i++){
FinalCount.increase();
System.out.println(FinalCount.y);
}
}
}
class Thread2 extends Thread{
public void run(){
for(int i=0;i<5;i++){
FinalCount.decrease();
System.out.println(FinalCount.y);
}
}
}
public class test {
public static void main(String[] args){
System.out.println(FinalCount.y);
Thread1 thread1a=new Thread1();
Thread1 thread1b=new Thread1();
Thread2 thread2a=new Thread2();
Thread2 thread2b=new Thread2();
thread1a.start();
thread1b.start();
thread2a.start();
thread2b.start();
}}
输出结果为:
1
2
3
4
5
6
7
8
9
10
11
10
9
8
7
6
5
4
3
2
1这样行了吧?
1.根本就不需要设置线程优先权,前两个线程肯定是优于后两个。
2.运行的顺序肯定是按他们定义的先后顺序。
3.因为这四个线程的run函数都是访问类FinalCount的synchronized函数,
类FinalCount的机锁同时只能有一个线程访问,当第一个线程thread1a在运行时,
其它的3个线程由于不拥有类FinalCount的机锁,因此只能等待。
(即使在第一个线程里循环1万次,或者sleep(1000),cpu也不会把运行权交给其它公用一个机锁的线程,除非你调用了对象的wait())问题1存在的问题是,“前两个线程肯定是优于后两个”,它们是被最先start,肯定是被优先“考虑”执行的,但是并不代表它们优先级别高,我前面说过,优先级不是先后的问题,而是在一个时间范围内被执行多少的概率问题。问题2存在的问题是,前面1提到“肯定是被优先“考虑”执行的”,仅仅是“优先考虑”,而不是说一定是这个顺序。问题3在表达上面存在模糊之处,含糊的地方是“即使在第一个线程里循环1万次”,不应该说在线程里循环,应该是在FinalCount类方法中CountCreate里头循环一万次这种说法才确切(如果按照你这种改法的话--就是把for循环放到FinalCount的CountCreate里头),在CountCreate里无论循环多少次还是sleep,只要没有走出这个被synchronized的方法体,机锁是不会被释放的。为了形象一些,可以对程序做出这样的改动:#######运行更改一:
public static synchronized void countCreate(){
try{
System.out.println("I will sleep....");
Thread.currentThread().sleep(1000);
}catch(Exception x){
}
for(int i=0;i<5;i++){
System.out.println(FinalCount.y);
--FinalCount.y;
}
}
结果是:
1
2
3
4
5
6
7
8
9
10
I will sleep....
11
10
9
8
7
I will sleep....
6
5
4
3
2
#######运行更改二:
class Thread1 extends Thread{ public void run(){
try{
System.out.println("i will sleep...");
sleep(50);
}catch(Exception x){
}
FinalCount.countCreate1();
}
}结果:
i will sleep...
i will sleep...
1
0
-1
-2
-3
-4
-5
-6
-7
-8
-9
-8
-7
-6
-5
-4
-3
-2
-1
0最后应该指出的是,诚然如 tiger999(不吃肉的老虎) 所说,是因为楼主老弟对线程的理解还不够准确和深刻,将for循环放入synchronized中并非一个灵活而且正确的解决方式,我将给出一个解决方案,如下帖。
public static void main(String[] args){
System.out.println(FinalCount.y);
Thread1 thread1a=new Thread1();
Thread1 thread1b=new Thread1();
Thread2 thread2a=new Thread2();
Thread2 thread2b=new Thread2();
thread2a.start();//这里将decrease 线程提前
thread1a.start();
thread1b.start();
thread2b.start();
}}运行结果是:
1
0
-1
-2
-3
-4
-3
-2
-1
0
1
2
3
4
5
6
5
4
3
2
1这种改法是很极端的改法,就是模拟了一种状态,两个加线程被block住(因为jvm的原因,几率虽然很小),thread2a被率先执行的这么一种情况。另外也可以这样改:
class Thread1 extends Thread{
public void run(){
try{
System.out.println("Sorry, I am blocked by unknown reason,damn JVM, sun can not ensure it...");
sleep(50);
}catch(Exception x){
}
for(int i=0;i<5;i++){
FinalCount.increase();
System.out.println(FinalCount.y);
}
}
}
private int y=1;
private int maxValue=10;//default max value
private int minValue=1;//default min value
private boolean releaseIncThreadFlag=false;//release flag for decrease thread
private boolean releaseDecThreadFlag=false;//release flag for increase thread
private boolean arriveMax=false;
public FinalCount(){
}
public FinalCount(int max,int min){
//if it is valid max-min releationship, override the default scenary
if(max>min){
maxValue=max;
minValue=min;
y=min;
}
} public synchronized void increase(){
//limitation control
if(y==maxValue)
return;
printY();
y++;
//increase to the max value, sets the control parameters and
//notify all waiting threads
if(y==maxValue){
releaseIncThreadFlag=true;
arriveMax=true;
printY();//print the top value
notifyAll();
}
}
public synchronized void decrease(){
//limitation control
if(y==minValue)
return;
y--;
printY();
//decrease to the min value, sets the control parameters and
//notify all waiting threads
if(y==minValue){
releaseDecThreadFlag=true;
arriveMax=false;
notifyAll();
}
}
private void printY(){
System.out.println("thread name=" + Thread.currentThread().getName());
System.out.println(y);
}
//wait() control method
public synchronized boolean isArriveMaxValue(){
return arriveMax;
}
//wait() control method
public synchronized boolean isReleaseIncThread(){
return releaseIncThreadFlag;
}
//wait() control method
public synchronized boolean isReleaseDecThread(){
return releaseDecThreadFlag;
}
//get the max value for loop count
public int getMaxValue(){
return maxValue;
}
}
class IncThread extends Thread{
FinalCount count;
public IncThread(String name,FinalCount count){
super(name);
this.count=count;
}
public void run(){
for(int i=0;i<count.getMaxValue();i++){
synchronized(count){
//for balance consideration and release increase thread...
while(count.isArriveMaxValue() & !count.isReleaseIncThread()){
try{
count.wait();
}catch(Exception x){
}
}
}
//if need to release current thread
if(count.isReleaseIncThread())
break;
count.increase();
}
//release prompt:
System.out.println("====== Thread(" + getName() + ") is released....");
}
}
class DecThread extends Thread{
FinalCount count;
public DecThread(String name,FinalCount count){
super(name);
this.count=count;
}
public void run(){
for(int i=0;i<count.getMaxValue();i++){
synchronized(count){
//when still not arrive at the max value,or still not release, waiting...
while(!count.isArriveMaxValue() & !count.isReleaseDecThread()){
try{
count.wait();
}catch(Exception x){
}
}
}
if(count.isReleaseDecThread())
break;
count.decrease();
}
System.out.println("====== Thread(" + getName() + ") is released....");
}
}
public class Test3 {
public static void main(String[] args){
FinalCount fc=new FinalCount();
//FinalCount fc=new FinalCount(30,1);
IncThread incThread1=new IncThread("incThread1",fc);
IncThread incThread2=new IncThread("incThread2",fc);
IncThread incThread3=new IncThread("incThread3",fc);
IncThread incThread4=new IncThread("incThread4",fc);
DecThread decThread1=new DecThread("decThread1",fc);
DecThread decThread2=new DecThread("decThread2",fc);
DecThread decThread3=new DecThread("decThread3",fc);
decThread2.start();//pay attention here!
decThread3.start();
incThread2.start();
incThread1.start();
incThread4.start();
incThread3.start();
decThread1.start();
}}运行结果:
===============================thread name=incThread2
1
thread name=incThread2
2
thread name=incThread2
3
thread name=incThread2
4
thread name=incThread1
5
thread name=incThread4
6
thread name=incThread3
7
thread name=incThread1
8
thread name=incThread4
9
thread name=incThread4
10
====== Thread(incThread3) is released....
thread name=decThread2
9
thread name=decThread3
8
thread name=decThread1
7
====== Thread(incThread4) is released....
====== Thread(incThread2) is released....
thread name=decThread2
====== Thread(incThread1) is released....
6
thread name=decThread3
5
thread name=decThread1
4
thread name=decThread1
3
thread name=decThread2
2
thread name=decThread1
1
====== Thread(decThread1) is released....
====== Thread(decThread2) is released....
====== Thread(decThread3) is released....======================================
这个解决方案更显得灵活,也能够完全确保数值由1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1这种顺序输出,而不论加减线程启动的先后,也可以将阈值设定在非1,10的任一一个范围,消除了不确定性,也充分利用了java提供的线程控制机制。如,可以这样改:
main函数中:
FinalCount fc=new FinalCount(13,12);
...
运行结果:
thread name=incThread2
12
thread name=incThread2
13
thread name=decThread2
12
====== Thread(decThread2) is released....
====== Thread(decThread3) is released....
====== Thread(incThread2) is released....
====== Thread(incThread1) is released....
====== Thread(incThread4) is released....
====== Thread(incThread3) is released....
====== Thread(decThread1) is released....
这个例子是使用java线程的一个非常好的范例,也是我为什么在上边的帖子中提到说这个问题精彩的原因所在。
public static void main(String[] args){ SharedData sd=new SharedData(); IncrementThread it1=new IncrementThread(sd);
IncrementThread it2=new IncrementThread(sd);
DecrementThread dt1=new DecrementThread(sd);
DecrementThread dt2=new DecrementThread(sd); dt1.start();
it1.start();
dt2.start();
it2.start();
}
} class IncrementThread extends Thread{
private SharedData sd=null;
public IncrementThread(SharedData sd){
this.sd=sd;
} public void run(){ for(int i=0;i<500;i++){
if(sd.whosRun==sd.INCREMENT_RUN)
System.out.println(sd.j++);
if(sd.j==1001){
sd.whosRun=sd.DECRMENT_RUN;
}
} }
} class DecrementThread extends Thread{
private SharedData sd=null;
public DecrementThread(SharedData sd){
this.sd = sd;
}
public void run(){
synchronized(sd){
while(sd.whosRun!=sd.DECRMENT_RUN){
try{
sd.wait();
}catch(Exception e){}
} for(int i=0;i<500;i++){
System.out.println(--sd.j);
}
}
}}class SharedData extends Thread{
public int j=1;
public final int INCREMENT_RUN=0;
public final int DECRMENT_RUN=1;
public volatile int whosRun=0;
public boolean running=true; public SharedData(){
this.setDaemon(true);
}
public void run(){ while(true){
if(whosRun==INCREMENT_RUN)
notifyAll();
}
}
}
To tiger999(不吃肉的老虎)大哥:
我运行你的程序,得出结果如下,只有递增过程,无递减。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
不是提醒过你把 synchronized( sd ) 去调吗!!!