碰到一个问题,用java并行地从三个文件中读取内容并写入到另一个文件中。思考了一下写了如下代码。
//Main.java
public class Main{
public static void main(String[] args){
String Wpath = "doc/d.txt";
new Thread(new Write("doc/a.txt",Wpath)).start();
new Thread(new Write("doc/b.txt",Wpath)).start();
new Thread(new Write("doc/c.txt",Wpath)).start();
}
}
主函数起三个线程并将读写路径传入线程对象中。
//Write.java
import java.io.*;
public class Write implements Runnable{
private String Rpath = null; //读路径
private String Wpath = null; //写路径
public Write(String R,String W){
Rpath = R;
Wpath = W;
}
public void run(){
RW rw = new RW();
String result = rw.read1(Rpath);//读文件
rw.write1(Wpath, result);//写文件
}
}
class RW{
public String read1(String Rpath){
File file = new File(Rpath);
String result = new String();
try{
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
while((s = br.readLine())!=null){
result += s;
}
br.close();
}
catch(Exception e){
e.printStackTrace();
}
return result;
}
public synchronized void write1(String Wpath,String result){
//for (int i = 0; i<8;i++) {
// System.out.println(i);
// Thread.yield();
//}
File file = new File(Wpath);
try{
BufferedWriter br = new BufferedWriter(new FileWriter(file,true));
if(result != null)
br.write(result);
br.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
不同的线程中根据不同读写路径创建不同线程读写文件。读取的文件是“i hava a pen ”;“i hava a apple”;"i hava a banana",但是写入的文本中出现了“i hava a penana”,说明共同写入的时候没有同步。可是在写入的函数中已经用synchronized同步锁修饰了。我添加了代码中的注释部分,发现有没有synchronized修饰结果都是不同步的,即都是并行的。
问题主要是什么?其实关键在于synchronized关键字锁住的是什么?当synchronized修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。即synchronized锁住的是对象,而所有被标记为synchronized的方法共享一个锁。《java编程思想》中这样描述:
而本文写的代码中run方法内创建了新的对象,所以每个线程都创建了自己的对象并执行,即使加了synchronized方法修饰也不会有影响。要解决这个问题需要在主线程中创建同一个对象然后供不同的线程使用。
修改后的代码为
//Main.java
public class Main{
public static void main(String[] args){
RW rw = new RW();
new Thread(new Write1(rw)).start();
new Thread(new Write2(rw)).start();
new Thread(new Write3(rw)).start();
}
}
//Write1.java
public class Write1 implements Runnable{
private RW rw = null;
public Write1(RW rw1){
rw = rw1;
}
public void run(){
String result = rw.read1("doc/a.txt");//读文件
rw.write1("doc/d.txt", result);//写文件
}
}
//Write2.java
public class Write2 implements Runnable{
private RW rw = null;
public Write2(RW rw1){
rw = rw1;
}
public void run(){
String result = rw.read1("doc/b.txt");//读文件
rw.write1("doc/d.txt", result);//写文件
}
}
//Write3.java
public class Write3 implements Runnable{
private RW rw = null;
public Write3(RW rw1){
rw = rw1;
}
public void run(){
String result = rw.read1("doc/c.txt");//读文件
rw.write1("doc/d.txt", result);//写文件
}
}
//RW.java
import java.io.*;
class RW{
public String read1(String Rpath){
File file = new File(Rpath);
String result = new String();
try{
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
while((s = br.readLine())!=null){
result += s;
}
br.close();
}
catch(Exception e){
e.printStackTrace();
}
return result;
}
public synchronized void write1(String Wpath,String result){
//for (int i = 0; i<8;i++) {
// System.out.println(i);
// Thread.yield();
//}
File file = new File(Wpath);
try{
BufferedWriter br = new BufferedWriter(new FileWriter(file,true));
if(result != null)
br.write(result);
br.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
这样问题就得到了解决。