鸟菜基础篇2012_10_28多线程(二)线程同步
2012-10-28 18:44
232 查看
半途而废终究不是个好习惯。回头翻翻自己博客,有几篇都是虎头蛇尾。虽然谈的内容很基础,还是不要三天打鱼两天晒网的好。对于一个初学者,最大的难题就是不知道如何开始。如果有些很好的而且简单的例子,先模仿再创造,这就好得多。就像我们小学时写作文,书读得多了,写起文章也就容易多了。所以,还是先给出简单的例子,有个开始,然后再慢慢深入。废话不多说,继续多线程部分。今天谈谈线程同步问题。
多线程肯定涉及并发,当某个程序块(临界区)某一时刻只允许一个线程访问时,就要涉及到线程同步问题。说的再直观一点,就是千军万马要过独木桥。必须要一个一个过,否则谁都别想过。如何保证临界区的同步访问呢?加锁。哪个线程获取了锁,其他线程就需要等待该锁被释放。这就保证了代码的同步性。下面介绍几种常用的锁。
1.synchronized
这个是java内置的锁。它锁的粒度是对象级别的。什么叫对象级别呢?就是一个对象里面有N个方法,都声明是用synchronized来同步,那么当一个方法被锁住以后,该对象内其他方法都无法再被访问。代码如下:
因为此处synchronized关键字锁的粒度是整个对象 syn,所以当syn中任意一个方法被调用时,其余所有方法都要等待该方法锁的释放,即任意时刻,add()和delete()方法只能有一个被访问。当我们创建另一个对象syn2时,该对象内add()/delete()方法同样不可以同时访问,但是syn.add()和syn2.add()是可以并发访问的,因为锁的粒度是对象,而不是整个类。
还有一种和synchronized几乎一样的锁:可重入锁 ReentrantLock。synchronized锁的范围隐含在它所包含的代码块区域内,可重入锁需要显示的指定加锁和解锁,更加灵活。在高并发程序中,可重入锁性能更高而且有中断功能。
下面贴一段用多线程读取文件代码,给出制定文件夹,多个线程读取文件夹下文件并处理,采用同步机制保证同一文件不会被多次读取。
多线程肯定涉及并发,当某个程序块(临界区)某一时刻只允许一个线程访问时,就要涉及到线程同步问题。说的再直观一点,就是千军万马要过独木桥。必须要一个一个过,否则谁都别想过。如何保证临界区的同步访问呢?加锁。哪个线程获取了锁,其他线程就需要等待该锁被释放。这就保证了代码的同步性。下面介绍几种常用的锁。
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 ")); } }
相关文章推荐
- Java多线程系列--“基础篇”10之 线程优先级和守护线程 (r)
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- python笔记10-多线程之线程同步(锁lock)
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- 多线程“基础篇”10之 线程优先级和守护线程
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- 鸟菜基础篇2012_09_23多线程(一)
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- SQL Server 2012入门T-SQL基础篇:(10)UPDATE语句
- Java多线程系列--【基础篇10】- 线程优先级和守护线程
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
- Java多线程系列--“基础篇”09之 interrupt()和线程终止方式
- 流行编程语言的详细对比(10)--线程同步
- Java多线程系列--“基础篇”01之 基本概念
- .Net Compact Framework 基础篇(10)--多语言程序的定制
- Java多线程系列--“基础篇”08之 join()
- 秒杀多线程第七篇 经典线程同步 互斥量Mutex