关于java线程同步的问题
我通过类newTicket里的变量state来同步三个线程,state=1时运行276:public synchronized void run_schwarz(String strcmd)这段代码,然后这段代码的末尾运行
314: state=2;
315: notifyAll(); ///!!!!!!!!!!!!!!!
来将state设为2,来运行第二段代码,但是从打印的结果来看,state始终等于1,第一个线程的调用了 p = rn.exec(schwarzexepath); 来执行一个exe,这个exe的执行结果是对的,但是为什么state没有改变呢?
求教各位高手,代码如下
20:
21:
22:public class winpcapMulti_bat extends HttpServlet
23:{
24:public void doGet(HttpServletRequest request, HttpServletResponse response)
25:throws IOException,ServletException
26:{
27:
28:
29:
30:
31:PrintWriter out=response.getWriter();
32:
33:
34:
35:out.write("<html>\r\n");
36:out.write("<head>\r\n");
×××××××××××××
60:
61:
62://
63:
64:String string_port_num;
65:BufferedReader in=new BufferedReader(new FileReader(netportlistfileName));
66:string_port_num=in.readLine();
67:in.close();
68:
69:out.write("string_port_num is "+string_port_num+"<p>");
70:
71://
72:/********************************************************************************/
73:newTickets t=new newTickets( string_port_num,netportexepath,sendpacketexepath,schwarzexepath,filelistname,schwarzcmdfilename , schwarzbatpath );
74: out.write("the filelistsize is"+t.getFilelistsize()+"<p>");
75:
76: out.write("the state is"+t.getState()+"<p>");
77: new Producer_schwarz(t).start();
78: out.write("the state is"+t.getState()+"<p>");
79: out.write("producer schwarz already run<p>");
80:
81:
82:new Consumer_netport(t).start();
83: out.write("the state is"+t.getState()+"<p>");
84:new Consumer_send(t).start();
85: out.write("the state is"+t.getState()+"<p>");
86:out.write("producer and two consumer already run");
87: out.write("the state is"+t.getState()+"<p>");
88:
89:/**********************************************************************************/
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:out.write("</body>\r\n");
100:out.write("</html>");
101:
102:
103:
104:
105:
106:
107:
108:
109:}//fun: doget
110:}//class
111:
112:
113:class newTickets
114:
115:{
116:
117:
118:
119:int state=1;
120:int filelistsize;
121:String string_port_num;
122:String netportexepath;
123:String sendpacketexepath;
124:String schwarzexepath;
125: String schwarzcmdfilename;
126: String schwarzbatpath;
127:
128:String filelistname;
129:
130:public newTickets(String string_port_num, String netportexepath,String sendpacketexepath, String schwarzexepath, String filelistname,String schwarzcmdfilename,String schwarzbatpath)
131:{
132:this.string_port_num=string_port_num;
133:this.netportexepath=netportexepath;
134:this.sendpacketexepath=sendpacketexepath;
135:this.schwarzexepath=schwarzexepath;
136:this.filelistname=filelistname;
137: this.schwarzcmdfilename=schwarzcmdfilename;
138:this.schwarzbatpath=schwarzbatpath;
139: this.state=1;
140:
141:readfilelist(filelistname);/// 获得需要采集的数据文件的个数
142:
143:}//constructor
144:
145:
146: public int getFilelistsize() /// 返回需要采集的数据文件的个数
147: {return filelistsize;}
148:
149: public int getState() /// 返回需要采集的数据文件的个数
150: {return state;}
151:
152:
153:void readfilelist(String filename)
154:{
155:
156:int filecount=0;
157:String tempstr;
158:try{
159:BufferedReader in=new BufferedReader(new FileReader(filename));
160:tempstr=in.readLine();
161:
162:while(tempstr!=null)
163:
164:{
165:tempstr=in.readLine();
166:filecount++;
167:}//while
168:in.close();
169:}//try
170:
171:catch(IOException iox){}
172:filelistsize=filecount;
173:
174:}//readfilelist
175:
176:
177:
178:public synchronized void run_sendpacket() //String string_port_num,String exepath are the member of the ticket class
179:
180:{
181:
182:if(state!=3)
183:try{wait();} catch(Exception e){}
184:
185:String temp_str_console;
186:OutputStream stdin = null;
187:InputStream stderr = null;
188:InputStream stdout = null;
189:
190:// launch EXE and grab stdin/stdout and stderr
191:
192:
193:
194:
195:Runtime rn = Runtime.getRuntime();
196:Process p = null;
197:try {
198:p = rn.exec(sendpacketexepath);
199:stdin = p.getOutputStream ();
200:stderr = p.getErrorStream ();
201:stdout = p.getInputStream ();
202:
203:// "write" the parms into stdin
204: temp_str_console = string_port_num + "\n";
205:stdin.write(temp_str_console.getBytes() );
206:stdin.flush();
207:
208:
209:stdin.close();
210:
211:
212:}catch (Exception e) {
213:// System.out.println(" couldn't exec netport sendpacket ");
214:}
215:
216:
217:state=1;
218:notifyAll();
219:
220:}//func
221:
222:
223:
224:
225:
226:
227:public synchronized void run_netport(String str_filename) //string_port_num is the member of the ticket class
228:
229:{
230:
231:if(state!=2)
232:try{wait();} catch(Exception e){}
233:
234:String temp_str_console;
235:OutputStream stdin = null;
236:InputStream stderr = null;
237:InputStream stdout = null;
238:
239:// launch EXE and grab stdin/stdout and stderr
240:
241:
242:
243:
244:Runtime rn = Runtime.getRuntime();
245:Process p = null;
246:try {
247:
248:p = rn.exec(netportexepath); // filename specified here
249:stdin = p.getOutputStream ();
250:stderr = p.getErrorStream ();
251:stdout = p.getInputStream ();
252:
253:// "write" the netportnum into stdin
254:temp_str_console = string_port_num + "\n";
255:stdin.write(temp_str_console.getBytes() );
256:stdin.flush();
257:// write the filename into stdin
258:temp_str_console = str_filename + "\n";
259:stdin.write(temp_str_console.getBytes() );
260:stdin.flush();
261:
262:
263:stdin.close();
264:
265:
266:}catch (Exception e) {
267:// System.out.println(" couldn't exec netport sendpacket ");
268:}
269:state=3;
270:notifyAll();
271:
272:}//fun
273:
274:
275:
276:public synchronized void run_schwarz(String strcmd)
277:{
278:
279:if(state!=1)
280:try{ wait();} catch(Exception e) {}
281:String temp_str_console;
282:OutputStream stdin = null;
283:InputStream stderr = null;
284:InputStream stdout = null;
285:
286:// launch EXE and grab stdin/stdout and stderr
287:
288:
289:
290:
291:Runtime rn = Runtime.getRuntime();
292:Process p = null;
293:
294: try{
295: FileWriter writer=new FileWriter(schwarzbatpath);
296:
297: writer.write(strcmd);
298: writer.close();
299: }catch(IOException e){}
300:
301: try {
302: p = rn.exec(schwarzexepath);
303:
304:
305:
306:
307:
308:
309:
310: }catch (Exception e) {
311:// System.out.println(" couldn't exec netport sendpacket ");
312:}//catch
313:
314: state=2;
315: notifyAll(); ///!!!!!!!!!!!!!!!
316:
317:}//func
318:
319:}//newTickets class
320:
321:
322:// schwarz use "if" and netport, sendpacket use "while"
323:
324:class Producer_schwarz extends Thread
325:{
326:newTickets t=null;
327:public Producer_schwarz(newTickets t)
328:{
329:this.t=t;
330:}
331:
332:public void run()
333:{
334:String cmdline;
335:String filelist=t.schwarzcmdfilename;
336:
337:try{
338:BufferedReader in=new BufferedReader(new FileReader(filelist));
339:cmdline=in.readLine();
340:
341:while(cmdline!=null)
342:
343:{
344:
345: String strcmd="g://sunAppPacket//controlschwarzsingle.exe 10.10.18.174 ";
346: strcmd=strcmd+cmdline;
347: strcmd=strcmd+"\r\n exit";
348:
349:t.run_schwarz(strcmd);
350:cmdline=in.readLine();
351:
352:
353:
354:
355:}//while
356:in.close();
357:}//try
358:
359:catch(IOException iox){}
360:
361:
362:}//run
363:}//class
364:
365:
366:
367:class Consumer_netport extends Thread // runs until read the fileist file over
368:
369:{
370:
371:newTickets t=null;
372:int i=0;
373:public Consumer_netport(newTickets t)
374:{this.t=t;}
375:public void run()
376:{
377:
378:
379:
380:
381:String filename;
382:String filelist=t.filelistname;
383:
384:try{
385:BufferedReader in=new BufferedReader(new FileReader(filelist));
386:filename=in.readLine();
387:
388:while(filename!=null)
389:
390:{
391:filename=in.readLine();
392:t.run_netport(filename);
393:}//while
394:in.close();
395:}//try
396:
397:catch(IOException iox){}
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:}//func run
411:
412:}//class
413:
414:
415:class Consumer_send extends Thread
416:
417:{
418:
419:newTickets t=null;
420:int i=0;
421:public Consumer_send(newTickets t)
422:{this.t=t;}
423:public void run()
424:{
425:while(++i<t.filelistsize) //whats the differece between while and if here? run_sendpacket is a single event, should be run multiple times
426:{
427:t.run_sendpacket();
428:}//while
429:}
430:
431:}//class
[解决办法]
好长的代码,看晕了。。。
把state改为 get/set 吧,不要直接对属性赋值,这样容易跟踪其变化情况。
另外,你依赖state做状态控制,但却没有进行同步,这个风险较高。
最少最少也应该使用violate进行定义。
最后,检查状态变化时,应该用循环而不是if:
while (getState()!=2) {
wait();
}
[解决办法]
楼上正解!
getter/setter是个好习惯,但在这个问题里,无伤大雅。volatile定义也是应该的。
最主要的就是,在轮询状态时,应该把if换成while。