• JAVA多线程编程中的并发和同步的问题
  • 波涛中的小船 发表于 2016/2/29 11:06:00 | 分类标签: 多线程 死锁 并发 同步 线程池
  • 在介绍并发之前我们先了解一下串行和并行:热闹的景点,买票人很多,这时只有一个窗口售票,大家排队依次买票就可以理解为串行。排队人太多了,旁边又加开了几个窗口,多人在不同的窗口同时买票可以理解为并行。

     如果只能开一个窗口,这时好多着急的人围上来,有问价格的,有掏钱的,又有取票的,在这个过程中售票员在同时应对多个买票人,可以理解为并发。

    我们经常在计算机上一边听歌一边写文档(或者处理其他的事情),这就是一种并发行为,表面看两个程序是同时进行,为什么不是并行呢?计算机只有一个CPU所以只能支持一个线程运行。有人拍砖说:我家里计算机是多核CPU可以同时支持多个线程运行,确实是这样,为此我也特地去百度了一下有如下几点认知:

    1、虽然是多核CPU但是,系统总线,内存是共用的,在加载内存数据时仍然需要串行访问。
    2、目前的程序设计语言仍然是过程型开发,没有和好的方法能自动的切割任务使并行计算。
    3、操作系统在线程调度时随着内核的增加复杂性递增,目前最多支持8核

    所以基于以上认知,我们在讨论并发和同步这个问题时仍然按照CPU单核来讨论。

    那么计算机是如何做到一边播放歌曲一边支持文档编辑呢?操作系统会把CPU的执行时间划分微妙级别的时间片段,每一个时间片内去调度一个线程执行,多个线程不断的切换执行,因此在人类可感知的时间段(秒级)内线程是同时执行的,所以多个线程在某个时间段内的同时执行就是并发。

    串行、并行和并发如下图所示:
     互联网应用基本上都是支持多用户多请求同时访问服务器端的,所以互联网应用都是支持并发的,那么高并发的主要困难是什么呢?操作系统会给每个线程分配独立的内存空间和时间片,所以线程间是隔离的。但是如果线程访问线程外的内存空间,文件系统,输入输出设备,数据库或者其他存储设备时就会发生资源竞争,共享资源的访问必须串行,保证串行访问资源的机制就是同步,JAVA中经常使用的同步机制有synchronized关键字,java.util.concurrent.locks.Lock系列类。

    同步的场景有以下几种:

    1、线程获取同步锁,获取失败则阻塞等待
    适用场景:

    a、同步获取序列号生成器,当有其他线程获取序列号时,其他线程等待

    java代码实例:
    public class SynchronizedProcessor implements Processor {
    /* (non-Javadoc)
    * @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
    */
    public void process(String name) {
    System.out.println(String.format("%s开始处理,当前时间是%d", name,
    System.currentTimeMillis()));
    synchronized (this) {
    System.out.println(String.format("%s获得锁%s", name,
    this.toString()));
    try {
    System.out.println(String.format("%s开始sleep", name));
    Thread.sleep(1000);
    System.out.println(String.format("%s结束sleep", name));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    System.out.println(String.format("%s释放锁%s", name,
    this.toString()));
    System.out.println(String.format("%s结束处理,当前时间是%d", name,
    System.currentTimeMillis()));
    }
    }
    2、线程获取同步锁,获取失败结束
    适用场景:
    a、定时任务,前一个处理线程未完成时,新线程不能获取锁则直接结束

    java代码示例:
    public class LockFailCloseProcessor implements Processor {
    private static Lock lock = new ReentrantLock();
    /* (non-Javadoc)
    * @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
    */
    public void process(String name) {
    System.out.println(String.format("%s开始处理,当前时间是%d", name,
    System.currentTimeMillis()));
    if (lock.tryLock()) {
    System.out.println(String.format("%s获得锁%s", name,
    this.toString()));
    try {
    System.out.println(String.format("%s开始sleep", name));
    Thread.sleep(1000);
    System.out.println(String.format("%s结束sleep", name));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    lock.unlock();
    System.out.println(String.format("%s释放锁%s", name,
    this.toString()));
    } else {
    System.out.println(String.format("%s没有获得锁直接退出",
    name));
    }
    System.out.println(String.format("%s结束处理,当前时间是%d", name,
    System.currentTimeMillis()));
    }
    }
    3、线程获取同步锁后,因为其他资源不满足暂时释放同步锁,等待唤醒
    适用场景:
    a、即使通讯中,发送者获取同步锁发现队列写满时,释放锁等待接收者读取数据

    java代码示例:
    public class SynchronizedWaitWriteProcessor implements Processor {
    /**
    * 是否可读标记,false:不可读,可写 true:可读,不可写
    */
    public static int maxSize = 5;
    public static List<String> content = new ArrayList<String>();
    /* (non-Javadoc)
    * @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
    */
    public void process(String name) {
    System.out.println(String.format("%s开始处理,当前时间是%d", name,
    System.currentTimeMillis()));
    synchronized (content) {
    System.out.println(String.format("%s获得锁%s", name,
    this.toString()));
    try {
    if (content.size() == maxSize) {
    System.out.println(
    String.format("%s临时释放锁%s", name, this.toString()));
    content.wait();
    }
    System.out.println(
    String.format("%s开始写入信息", name));
    Random random = new Random();
    for (int i = 0; i < maxSize; i++) {
    content.add(
    String.format("写入信息%d", random.nextInt(1000)));
    }
    System.out.println(
    String.format("%s结束写入信息", name));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    content.notify();
    }
    System.out.println(String.format("%s释放锁%s", name,
    this.toString()));
    System.out.println(String.format("%s结束处理,当前时间是%d", name,
    System.currentTimeMillis()));
    }
    }
    4、线程获取同步锁后,因为其他资源不满足结束线程

    适用场景:
    a、即使通讯中,接收者获取同步锁发现队列无数据时,释放锁结束线程
    java代码示例:

    public class SynchronizedWaitReadProcessor implements Processor {
    /* (non-Javadoc)
    * @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
    */
    public void process(String name) {
    System.out.println(String.format("%s开始处理,当前时间是%d", name,
    System.currentTimeMillis()));
    synchronized (SynchronizedWaitWriteProcessor.content) {
    System.out.println(String.format("%s获得锁%s", name,
    this.toString()));
    if (SynchronizedWaitWriteProcessor.content.size()
    != 0) {
    System.out.println(
    String.format("%s开始读出信息", name));
    for (int i = 0;
    i < SynchronizedWaitWriteProcessor.content.size(); i++) {
    System.out.println("读出信息:" + SynchronizedWaitWriteProcessor.content.get(i));
    }
    System.out.println(
    String.format("%s结束读出信息", name));
    }
    SynchronizedWaitWriteProcessor.content.notify();
    }
    System.out.println(String.format("%s释放锁%s", name,
    this.toString()));
    System.out.println(String.format("%s结束处理,当前时间是%d", name,
    System.currentTimeMillis()));
    }
    }
      的main和Processor :

    public interface Processor {
    public void process(String name);
    }
    public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
    //试SynchronizedProcessor
    // Processor processor = new SynchronizedProcessor();
    // for (int i = 0; i < 10; i++) {
    // ProcessorThread threadProcessor =
    new ProcessorThread("name" + i, processor);
    // threadProcessor.start();
    // }
    //试LockProcessor
    // Processor processor = new LockProcessor();
    // for (int i = 0; i < 10; i++) {
    // ProcessorThread threadProcessor =
    new ProcessorThread("name" + i, processor);
    // threadProcessor.start();
    // }
    // Processor processor = new LockFailCloseProcessor();
    // for (int i = 0; i < 10; i++) {
    // ProcessorThread threadProcessor =
    new ProcessorThread("name" + i,
    // processor);
    // threadProcessor.start();
    // }
    Processor readProcessor = new SynchronizedWaitReadProcessor();
    ProcessorThread readThreadProcessor =
    new ProcessorThread("read", readProcessor);
    readThreadProcessor.start();
    Processor writeProcessor = new SynchronizedWaitWriteProcessor();
    ProcessorThread writeThreadProcessor =
    new ProcessorThread("write", writeProcessor);
    writeThreadProcessor.start();
    Thread.sleep(100);
    ProcessorThread read2ThreadProcessor =
    new ProcessorThread("read2", readProcessor);
    read2ThreadProcessor.start();
    }
    }
    多线程可以大大提高性能,但是多线程的同步又增加了应用的复杂性,是否能平衡多线程的性能和复杂性是是否有高并发经验的要求。
  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:波涛中的小船
  • 加入时间:2013/6/5 0:00:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮