Java多线程编程

用多线程处理以下场景:
  1. 文件中有原始数据,通过一个线程 T1监控文件路径,把原始数据读到同步队列Q1中。
  2. 线程T2读取Q1中的数据并处理把结果放到同步队列Q2中,等待子线程T2处理。
  3. 在T2中开N个子线程T3处理Q2的数据,并把处理结果放到同步集合Set3中。
  4. 线程T2汇总其本身及子线程T3处理的结果放到同步队列Q4中
  5. 线程T4把Q4中的数据输出到文件中。
流程图大致如下:
Java多线程编程_第1张图片
所以要考虑的问题:
  1. 怎样去管理线程及线程间的关系?
  2. 同步队列用java提供的什么同步集合?
对问题1,考虑把所有的线程放到一个线程池中去处理。
对问题2,考虑的同步集合有 LinkedBlockingQueue ConcurrentLinkedQueue
代码 :T1,T2,T3,T4代码
https://github.com/kntao/code-snippets/tree/master/java/%E5%A4%9A%E7%BA%BF%E7%A8%8B
Java同步机制实现的方式

  1. java.lang.ThreadLocal
同ThreadLocal 创建一个线程的局部变量副本,
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-11-23
 * Time: 10:45:02
 * 学生
 */
public class Student {
    private int age = 0;   //年龄
 
    public int getAge() {
        return this.age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
 
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-11-23
 * Time: 10:53:33
 * 多线程下测试程序
 */
public class ThreadLocalDemo implements Runnable {
    //创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
    private final static ThreadLocal studentLocal = new ThreadLocal();
 
    public static void main(String[] agrs) {
        ThreadLocalDemo td = new ThreadLocalDemo();
        Thread t1 = new Thread(td, "a");
        Thread t2 = new Thread(td, "b");
        t1.start();
        t2.start();
    }
 
    public void run() {
        accessStudent();
    }
 
    /**
     * 示例业务方法,用来测试
     */
    public void accessStudent() {
        //获取当前线程的名字
        String currentThreadName = Thread.currentThread().getName();
        System.out.println(currentThreadName + " is running!");
        //产生一个随机数并打印
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println("thread " + currentThreadName + " set age to:" + age);
        //获取一个Student对象,并将随机数年龄插入到对象属性中
        Student student = getStudent();
        student.setAge(age);
        System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());
    }
 
    protected Student getStudent() {
        //获取本地线程变量并强制转换为Student类型
        Student student = (Student) studentLocal.get();
        //线程首次执行此方法的时候,studentLocal.get()肯定为null
        if (student == null) {
            //创建一个Student对象,并保存到本地线程变量studentLocal中
            student = new Student();
            studentLocal.set(student);
        }
        return student;
    }
}
运行结果:
a is running! 
thread a set age to:76 
b is running! 
thread b set age to:27 
thread a first read age is:76 
thread b first read age is:27 
thread a second read age is:76 
thread b second read age is:27 
 2.   Synchronized    
Synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。假如再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。 
在进一步阐述之前,我们需要明确几点: 
A.无论synchronized关键字加在方法上还是对象上,他取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。 
B.每个对象只有一个锁(lock)和之相关联。 
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。 
3. Lock和Condition实现了线程的另一种同步和互斥
[java]  view plain copy
  1. package com.eshroe.sweetop.concurrency;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4. import java.util.concurrent.TimeUnit;  
  5. import java.util.concurrent.locks.Condition;  
  6. import java.util.concurrent.locks.Lock;  
  7. import java.util.concurrent.locks.ReentrantLock;  
  8. class Car2 {  
  9.     private Lock lock = new ReentrantLock();  
  10.     private Condition condition = lock.newCondition();  
  11.     private boolean waxOn = false;  
  12.     public void waxed() {  
  13.         lock.lock();  
  14.         try {  
  15.             waxOn = true;  
  16.             condition.signalAll();  
  17.         } finally {  
  18.             lock.unlock();  
  19.         }  
  20.     }  
  21.     public void buffed() {  
  22.         lock.lock();  
  23.         try {  
  24.             waxOn = false;  
  25.             condition.signalAll();  
  26.         } finally {  
  27.             lock.unlock();  
  28.         }  
  29.     }  
  30.     public void waitForWaxing() throws InterruptedException {  
  31.         lock.lock();  
  32.         try {  
  33.             while (waxOn == false) {  
  34.                 condition.await();  
  35.             }  
  36.         } finally {  
  37.             lock.unlock();  
  38.         }  
  39.     }  
  40.     public void waitForBuffing() throws InterruptedException {  
  41.         lock.lock();  
  42.         try {  
  43.             while (waxOn == true) {  
  44.                 condition.await();  
  45.             }  
  46.         } finally {  
  47.             lock.unlock();  
  48.         }  
  49.     }  
  50. }  
  51. class WaxOn2 implements Runnable {  
  52.     private Car2 car;  
  53.     public WaxOn2(Car2 car) {  
  54.         this.car = car;  
  55.     }  
  56.     public void run() {  
  57.         try {  
  58.             while (!Thread.interrupted()) {  
  59.                 System.out.println("Wax On!");  
  60.                 TimeUnit.MILLISECONDS.sleep(200);  
  61.                 car.waxed();  
  62.                 car.waitForBuffing();  
  63.             }  
  64.         } catch (InterruptedException e) {  
  65.             System.out.println("Exiting via interrupt");  
  66.         }  
  67.         System.out.println("Ending Wax On task");  
  68.     }  
  69. }  
  70. class WaxOff2 implements Runnable {  
  71.     private Car2 car;  
  72.     public WaxOff2(Car2 car) {  
  73.         this.car = car;  
  74.     }  
  75.     public void run() {  
  76.         try {  
  77.             while (!Thread.interrupted()) {  
  78.                 car.waitForWaxing();  
  79.                 System.out.println("Wax Off");  
  80.                 TimeUnit.MILLISECONDS.sleep(200);  
  81.                 car.buffed();  
  82.             }  
  83.         } catch (InterruptedException e) {  
  84.             System.out.println("Exiting via interrupt");  
  85.         }  
  86.         System.out.println("Ending Wax Off task");  
  87.     }  
  88. }  
  89. public class WaxOMatic2 {  
  90.     public static void main(String[] args) throws InterruptedException {  
  91.         Car2 car = new Car2();  
  92.         ExecutorService exec = Executors.newCachedThreadPool();  
  93.         exec.execute(new WaxOn2(car));  
  94.         exec.execute(new WaxOff2(car));  
  95.         TimeUnit.SECONDS.sleep(5);  
  96.         exec.shutdownNow();  
  97.     }  
  98. }  
4. volatile关键字
 
  volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。    
谈谈并发集合
线程安全的集合:HashTable,ConcurrentHashMap,LinkedBlockingQueue,ConcurrentLinkedQueue,Collections.synchronizedSet(new HashSet<String>);

HashTable是线程安全的,是 使用synchronized来保证线程安全的, 在线程竞争激烈的时候,它的效率相当低,因为它们是在争同一把锁,而 ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
LinkedBlockingQueue,ConcurrentLinkedQueue,一个是阻塞队列,一个是并发队列(非阻塞方式)。
祥见:http://www.infoq.com/cn/articles/ConcurrentLinkedQueue






你可能感兴趣的:(Java多线程编程)