您的位置:首页 > 其它

鸟菜基础篇2012_10_28多线程(二)线程同步

2012-10-28 18:44 232 查看
半途而废终究不是个好习惯。回头翻翻自己博客,有几篇都是虎头蛇尾。虽然谈的内容很基础,还是不要三天打鱼两天晒网的好。对于一个初学者,最大的难题就是不知道如何开始。如果有些很好的而且简单的例子,先模仿再创造,这就好得多。就像我们小学时写作文,书读得多了,写起文章也就容易多了。所以,还是先给出简单的例子,有个开始,然后再慢慢深入。废话不多说,继续多线程部分。今天谈谈线程同步问题。

多线程肯定涉及并发,当某个程序块(临界区)某一时刻只允许一个线程访问时,就要涉及到线程同步问题。说的再直观一点,就是千军万马要过独木桥。必须要一个一个过,否则谁都别想过。如何保证临界区的同步访问呢?加锁。哪个线程获取了锁,其他线程就需要等待该锁被释放。这就保证了代码的同步性。下面介绍几种常用的锁。

1.synchronized

这个是java内置的锁。它锁的粒度是对象级别的。什么叫对象级别呢?就是一个对象里面有N个方法,都声明是用synchronized来同步,那么当一个方法被锁住以后,该对象内其他方法都无法再被访问。代码如下:

public class SynChronizedExample implements Runnable {
private volatile int num = 0;

@Override
public void run() {
// 当add()/delete()在任一时刻,仅允许一个方法被访问
while (true) {
add();
delete();
}
}

/*
* add()和delete() 锁的粒度暗含为 this 当前对象
*/
public synchronized void add() {
num++;
System.out.print(num);
}

public synchronized void delete() {
num--;
System.out.print(num);
}

public static void main(String[] args) {
SynChronizedExample syn = new SynChronizedExample();
new Thread(syn, "线程1").start();
new Thread(syn, "线程2").start();
}
}


因为此处synchronized关键字锁的粒度是整个对象 syn,所以当syn中任意一个方法被调用时,其余所有方法都要等待该方法锁的释放,即任意时刻,add()和delete()方法只能有一个被访问。当我们创建另一个对象syn2时,该对象内add()/delete()方法同样不可以同时访问,但是syn.add()和syn2.add()是可以并发访问的,因为锁的粒度是对象,而不是整个类。

还有一种和synchronized几乎一样的锁:可重入锁 ReentrantLock。synchronized锁的范围隐含在它所包含的代码块区域内,可重入锁需要显示的指定加锁和解锁,更加灵活。在高并发程序中,可重入锁性能更高而且有中断功能。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SynChronizedExampleII implements Runnable {
private volatile int num = 0;
private Lock lock = new ReentrantLock();//可重入锁

@Override
public void run() {
// 当add()/delete()在任一时刻,需要获取 lock
while (true) {
add();
delete();
}
}

/*
* add()和delete()方法采用了可重入锁
*/
public void add() {

try {
lock.lock();
num++;
System.out.print(num);
} finally {
lock.unlock(); //必须写在 finally语句块中
}
}

public void delete() {
try {
lock.lock();
num--;
System.out.print(num);
} finally {
lock.unlock();
}
}

public static void main(String[] args) {
SynChronizedExampleII syn = new SynChronizedExampleII();
new Thread(syn, "线程1").start();
new Thread(syn, "线程2").start();
}
}


下面贴一段用多线程读取文件代码,给出制定文件夹,多个线程读取文件夹下文件并处理,采用同步机制保证同一文件不会被多次读取。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class WeatherMultThread implements Runnable {
// 文件锁
private ReentrantLock fileLock = new ReentrantLock();
private ReentrantLock recordLock = new ReentrantLock();

private volatile int peak;           // 最大差值
private volatile int fileIndex;      // 每次读取文件数组下标
private final File[] eachFile;       // 每个城市文件夹
private final BufferedWriter writer; // 输出文件

public WeatherMultThread(String dirname, String rsFileName)	throws Exception {
this.eachFile = new File(dirname).listFiles();
this.writer = new BufferedWriter(new FileWriter(new File(rsFileName)));
}

// 每次取一个文件夹
@Override
public void run() {
while (true) {
try {
//每个线程 轮流取文件   同步抓取 保证同一个文件不会被重复抓
File f = getEachDayFile(eachFile);
System.out.println("线程 " + Thread.currentThread().getName() + "抓取" + f.getName());
dealEachDayFile(f);// 先抓一个 然后去处理
} catch (Exception e) {
break;// 越界就跳出
}
}
try {
writer.append(" peak:" + peak);
writer.close();
} catch (Exception e) {
} finally {
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");// 设置日期格式
System.out.println(df.format(new Date()));// new Date()为获取当前系统时间
Thread.currentThread().interrupt();// 停止当前线程
}
}

// 保证每个线程抓取不同的 每个文件夹
protected File getEachDayFile(final File[] each) {
try {
fileLock.lock();
return each[fileIndex++];
} finally {
fileLock.unlock();
}
}

// 处理每个txt文件内容 每个文件格式"max:1 min:-1"中间为空格
protected void dealEachDayFile(final File eachDayFile) {
try {
String temp = null;
BufferedReader reader = new BufferedReader(new FileReader(eachDayFile));
reader.skip(4);
while ((temp = reader.readLine()) != null) {
int max = Integer.valueOf(temp.substring(0, temp.indexOf(" ")));
int min = Integer.valueOf(temp.substring(temp.indexOf(":") + 1));
this.setResult(max - min);
}
reader.close();
} catch (Exception e) {
}
}

//
protected void setResult(int peak) {
try{
recordLock.lock();
if (peak > this.peak) {
this.peak = peak;
}
}finally{
recordLock.unlock();
}
}

public static void main(String[] args) throws Exception {

SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");// 设置日期格式
System.out.println(df.format(new Date()));// new Date()为获取当前系统时间

String filename = "E:/weather";  //输入路径
String rsFilename = "E:/rs.txt"; //输出文件

WeatherMultThread weatherThread = new WeatherMultThread(filename,rsFilename);
//用多线程处理
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.submit(new Thread(weatherThread, "线程1 "));
pool.submit(new Thread(weatherThread, "线程2 "));
pool.submit(new Thread(weatherThread, "线程3 "));

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: