今天遇到一个问题,需要多个线程读取同一个文件的不同位置,提高效率,写代码验证了一下,把结果记录下来。
首先我们写个文件,然后多线程读取,以下是我实验的代码:
package com.alibaba.middleware.race;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Test2 {
public static void main(String[] args) throws IOException {
byte[] th1 = "线程1".getBytes();
byte[] th2 = "线程2".getBytes();
byte[] th3 = "线程3".getBytes();
final int len = th1.length;
final RandomAccessFile raf = new RandomAccessFile(
"F:/tianchi/index.data", "rw");
raf.seek(1);
raf.write(th1);
raf.seek(200);
raf.write(th2);
raf.seek(300);
raf.write(th3);
Runnable runnable1 = new Runnable() {
@Override
public void run() {
while (true) {
byte[] b = new byte[len];
try {
raf.seek(1);
raf.read(b);
if ("线程1".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程1-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
while (true) {
try {
byte[] b = new byte[len];
raf.seek(200);
raf.read(b);
if ("线程2".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程2-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Runnable runnable3 = new Runnable() {
@Override
public void run() {
while (true) {
try {
byte[] b = new byte[len];
raf.seek(300);
raf.read(b);
if ("线程3".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程3-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
for (int i = 0; i < 20; i++) {
new Thread(runnable1).start();
new Thread(runnable2).start();
new Thread(runnable3).start();
}
System.out.println("主线程完了");
}
}
测试结果如下,会出现这样的问题:
ok
线程3-
线程1-线程3
ok
ok
说明,多个线程读取同一个文件,不加锁,是会出错的。
然后我们做如下改进。
代码:
package com.alibaba.middleware.race;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Test2 {
public static void main(String[] args) throws IOException {
byte[] th1 = "线程1".getBytes();
byte[] th2 = "线程2".getBytes();
byte[] th3 = "线程3".getBytes();
final int len = th1.length;
final RandomAccessFile raf = new RandomAccessFile(
"F:/tianchi/index.data", "rw");
raf.seek(1);
raf.write(th1);
raf.seek(200);
raf.write(th2);
raf.seek(300);
raf.write(th3);
Runnable runnable1 = new Runnable() {
@Override
public void run() {
while (true) {
byte[] b = new byte[len];
try {
synchronized (raf) {
raf.seek(1);
raf.read(b);
}
if ("线程1".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程1-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
while (true) {
try {
byte[] b = new byte[len];
synchronized (raf) {
raf.seek(200);
raf.read(b);
}
if ("线程2".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程2-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Runnable runnable3 = new Runnable() {
@Override
public void run() {
while (true) {
try {
byte[] b = new byte[len];
synchronized (raf) {
raf.seek(300);
raf.read(b);
}
if ("线程3".equals(new String(b))) {
System.out.println("ok");
} else {
System.out.println("线程3-" + new String(b));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
for (int i = 0; i < 20; i++) {
new Thread(runnable1).start();
new Thread(runnable2).start();
new Thread(runnable3).start();
}
System.out.println("主线程完了");
}
}
对文件的访问加一个锁,这样就可以了,测试结果是对的,我就不贴了。