Java并发编程初体验(一)

一.前言
操作系统的出现使得计算机每次能运行多个运行程序,并且不同的程序都在单独的进程中运行;操作系统为各个独立执行的进程分配各种资源,包括内存、文件句柄以及安全证书等。如果需要的话,在不同的进程之间可以通过一些粗粒度的通信机制来交换数据,包括:套接字、信号处理器、共享内存、信号量以及文件等。
之所以在计算机中加入操作系统来实现多个程序的同时执行,主要是基于以下原因:
资源利用率:在某些情况下,程序必须等待某个外部操作执行完成,例如输入操作或输出操作等,而在等待是程序无法执行其他任何工作。因此,如果在等待的同时可以运行另一个程序,那么无疑将提高资源的利用率。
公平性:不同的用户和程序对于计算机上的资源有着同等的使用权。一种高效的运行方式是通过粗粒度的时间分片(time slicing)使这些用户和程序能够共享计算机资源,而不是由一个程序从头执行到尾,然后再启动下一个程序。
便利性:通常来说,在计算多个任务时,每个程序执行一个任务,并在必要时相互通信,这相比一个程序执行所有任务更容易实现。
线程也被称为轻量级进程,在大多数现代操作系统中,都是以线程为基本的调度单位,而不是进程。如果没有明确的协同机制,那么线程就将彼此独立执行。由于同一个进程中的所有线程都将共享进程中的内存地址空间,因此这些线程都能访问相同的变量并在同一个堆上分配对象,这就需要实现一种比在进程内共享数据粒度更细的数据共享机制。如果没有明确的同步机制来协同对共享数据的访问,那么当一个线程正在使用某个变量时,另一个线程可能同时访问这个变量,这将造成不可预测的后果.
二.线程的优势
1.发挥多处理器的强大能力
2.建模的简单性,每个线程执行一种类型的任务,相比于一个线程执行多个任务在程序的设计上要简单很多
3.异步事件的简化处理,服务器应用程序接受多个来自远程客户端的套接字连接请求时,如果为每个连接都分配其各自的线程并使用同步I/O,那么会降低这些程序的开发难度。
三.线程带来的风险
1.安全性问题:线程安全性问题是很复杂的,在没有充足同步的情况下,多个线程中的操作执行顺序是不可预测的,甚至会产生奇怪的结果。
2.活跃性问题:在开发并发代码时,一定要注意线程安全性时不可破坏的。安全性不仅对多线程程序很重要,对于单线程程序同样重要。安全性的含义是永远不发生糟糕的事情,活跃性则关注于另一个目标,某件正确的事情最终会发生。死锁、饥饿、活锁等都是常见的活跃性问题。
3.性能问题:与活跃性问题密切相关的是性能问题。活跃性意味着某件正确的事情最终会发生,但不够好,因为我们希望正确的事情尽快发生。性能问题包括多个方面,比如:服务时间过长,响应不灵敏,吞吐率太低,资源消耗过高或者可伸缩性较低等。多线程环境中,频繁的上下文切换(context switch)会带来极大的开销;共享数据的同步机制会使得内存缓存区数据失效,抑制编译器优化,一起多了数据同步的一些操作,这些往往都会带来更大的性能开销。
四.并发编程示例体验
下面是一个计数器示例:有1000个线程,线程并发量设置为100,执行计数功能,看下结果

public static int num=0;
    public static int ThreadPoolNum=1000;//线程数量
    private static  int PREMITS=2;//线程并发的信号量
    public static void main(String[] args) {
        final Semaphore semaphore = new Semaphore(PREMITS);
        ExecutorService executorService = Executors.newCachedThreadPool();//线程池
        for(int i=0;i<ThreadPoolNum;i++){
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        num++;
                        System.out.println("结果num:"+num);
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        executorService.shutdown();
    }

发现每次运行结果都不一样,比如997 998 991 …,但是基本没看到过1000的,一起来感受一下并发编程吧

猜你喜欢

转载自blog.csdn.net/u010520146/article/details/84063933