在JAVA中并行和并发机制的区别?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在JAVA中并行和并发机制的区别?相关的知识,希望对你有一定的参考价值。

参考技术A

在JAVA中并行和并发机制的区别?

并发与并行是两个既相似而又不相同的概念:并发性,又称共行性,是指能处理多个同时性活动的能力;并行是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行,也亦是说并发事件之间不一定要同一时刻发生。
-------------------------------------------------------------
并发和并行的区别仅仅在发生时刻的不同吗?
举个例子理解一下,如:
假设有A、B 两个事件
并行:
如果A和B都在15:30同时发生,A 的运行时间为 5 分钟,B 的运行时间为 8 分钟
在前5分钟是并行,也包括并发,因为他们都是在同一时刻发生的
并发:
如果A在15:30发生,运行3分钟后,B事件发生,在以后的5分钟时间里,A和B 是并发的
-------------------------------------------------------------
并发,是在同一个cpu上同时(不是真正的同时,而是看来是同时,因为cpu要在多个程序间切换)运行多个程序。
并行,是每个cpu运行一个程序。
打个比方,并发,就像一个人(cpu)喂2个孩子(程序),轮换着每人喂一口,表面上两个孩子都在吃饭。
并行,就是2个人喂2个孩子,两个孩子也同时在吃饭。

jvm gc 并行和并发的区别

并行(Parallel):多条垃圾收集线程并行工作,而用户线程仍处于等待状态
并发(Concurrent):垃圾收集线程与用户线程一段时间内同时工作(交替执行)

java中并行与并发的区别?

并行和并发 与Java无关,这是操作系统级别的概念。并发,就像一个人(CPU)喂 n 个孩子(程序),轮换着每人喂一口,从表面上看两个孩子都在吃饭;而并行,就是 n 个人(CPU)喂 n 个孩子(程序),n 个孩子也同时在吃饭。

sql server和oracle并发控制机制的区别

一、开放性
1、SQL Server 只能在windows上运行,没有丝毫的开放性,操作系统的系统的稳定对数据库是十分重要的。Windows9X系列产品是偏重于桌面应用,NT server只适合中小型企业。而且windows平台的可靠性,安全性和伸缩性是非常有限的。它不象unix那样久经考验,尤其是在处理大数据库。
2、 Oracle 能在所有主流平台上运行(包括 windows)。完全支持所有的工业标准。采用完全开放策略。可以使客户选择最适合的解决方案。对开发商全力支持。
二、可伸缩性,并行性
1、SQL server 并行实施和共存模型并不成熟,很难处理日益增多的用户数和数据卷,伸缩性有限。
2、Oracle 并行服务器通过使一组结点共享同一簇中的工作来扩展windownt的能力,提供高可用性和高伸缩性的簇的解决方案。如果windowsNT不能满足需要,用户可以把数据库移到UNIX中。Oracle的并行服务器对各种UNIX平台的集群机制都有着相当高的集成度。
三、性能
1、SQL Server 多用户时性能不佳
2、Oracle 性能最高, 保持开放平台下的TPC-D和TPC-C的世界记录。
四、客户端支持及应用模式
1、SQL Server C/S结构,只支持windows客户,可以用ADO、DAO、OLEDB、ODBC连接。
2、Oracle 多层次网络计算,支持多种工业标准,可以用ODBC、JDBC、OCI等网络客户连接。
五、操作简便
1、 SQL Server 操作简单,但只有图形界面。
2、Oracle 较复杂,同时提供GUI和命令行,在windowsNT和unix下操作相同。
六、使用风险
1、SQL server 完全重写的代码,经历了长期的测试,不断延迟,许多功能需要时间来证明。并不十分兼容。
2、Oracle 长时间的开发经验,完全向下兼容。得到广泛的应用。完全没有风险。 最后价格上 ORACLE贵过SQLSRVER。

php有并发机制吗

不同的设备肯定session是独立的。session的实现的机制是,浏览器第一次访问,不包含任何cookie,服务器随机生成一个sessionid作为cookie返回客户端。
之后的访问,浏览器带上这个cookie,服务器视作是同一个会话。
可见,如果不同的计算机,session肯定不同。

什么是Hibernate的并发机制?

Hibernate并发机制:
a、Hibernate的Session对象是非线程安全的,对于单个请求,单个会话,单个的工作单元(即单个事务,单个线程),它通常只使用一次,然后就丢弃。
如果一个Session 实例允许共享的话,那些支持并发运行的,例如Http request,session beans将会导致出现资源争用。
如果在Http Session中有hibernate的Session的话,就可能会出现同步访问Http Session。只要用户足够快的点击浏览器的“刷新”,就会导致两个并发运行的线程使用同一个Session。
b、多个事务并发访问同一块资源,可能会引发第一类丢失更新,脏读,幻读,不可重复读,第二类丢失更新一系列的问题。

python并发和java并发的区别

使用tornado的前提是你的服务是IO密集型的,并且你得写异步api,也可以请参考我签名中的框架,把tornado改造成eventloop+threadpool (GitHub - nikoloss/iceworld: tonado的multi-thread 多线程封装)。我们公司的android ios wap后台全是这套框架在提供服务。目前已经切换到一个分布式响应群组里面了,此时tornado只是作为一个中继的gateway存在:GitHub - nikoloss/cellnest: 分布式service
在没有阻塞的情况下,python的性能肯定不如编译型语言。这种全异步的模型的优势也无法体现出来,一旦有IO操作了,这种全异步模型的第一步apet新连接的操作并不会暂停,也就是只要有内容抵达,至少ioloop这个环节是可以照单全收的,接收之后协程处理,随着并发量增长它的性能下降是平稳且平滑的。反观线程模型,如果消费数据赶不上新连接新数据的生产,性能就会直线下降。
你的700qps差不多,你可以换3.1或者3.2的tornado试试,1100~1400应该可以跑出来。当然追求一个静态文本的输出性能是否有必要,我觉得实际情况比这种单纯的压测要复杂的多。

OS之并发与并行,异步和多线程的区别

1、并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
2、并行:在操作系统中,一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。
3、多线程:多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。
4、异步:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。
5、异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或则交给另外的进程来处理。

什么是Hibernate的并发机制?怎么去处理并发问题?

a、Hibernate的Session对象是非线程安全的,对于单个请求,单个会话,单个的工作单元(即单个事务,单个线程),它通常只使用一次, 然后就丢弃。 如果一个Session 实例允许共享的话,那些支持并发运行的,例如Http request,session beans将会导致出现资源争用。 如果在Http Session中有hibernate的Session的话,就可能会出现同步访问Http Session。只要用户足够快的点击浏览器的“刷新”, 就会导致两个并发运行的线程使用同一个Session。 b、多个事务并发访问同一块资源,可能会引发第一类丢失更新,脏读,幻读,不可重复读,第二类丢失更新一系列的问题。 解决方案:设置事务隔离级别。 Serializable:串行化。隔离级别最高 Repeatable Read:可重复读 Read Committed:已提交数据读 Read Unmitted:未提交数据读。隔离级别最差 设置锁:乐观锁和悲观锁。 乐观锁:使用版本号或时间戳来检测更新丢失,在 的映射中设置 optimistic-lock=all可以在没有版本或者时间戳属性映射的情况下实现 版本检查,此时Hibernate将比较一行记录的每个字段的状态 行级悲观锁:Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!只要为JDBC连接指定一下隔 离级别,然后让数据库去搞定一切就够了。类LockMode 定义了Hibernate所需的不同的锁定级别:LockMode.UPGRADE,LockMode.UPGRADE_NOWAIT,LockMode.READ;

Java并发编程基础

并发与并行

并发与并行的区别?

并发:同时完成多个任务,无需等待当前任务完成即可执行其它任务。例如解决IO密集型任务。

并行:同时在多个CPU中执行多个任务,将任务分为多个部分,在多个CPU中执行多个子任务。用于解决CPU密集型任务。

总之,并发(并行)是为了减少等待(阻塞)时间的技术

举个例子来说明单线程,并发,并行的区别:

小明正在听歌,她妈妈让他做作业,这时,小明...

  • 先把歌听完了,再开始写作业,小明就是单线程的
  • 暂停歌曲播放,开始写作业,1分钟后停止写作业,开始播放音乐,如此反复,小明就是并发的
  • 一边听歌,一边写作业,小明就是并行的

什么时候应该使用并发?

  • 永远不要使用并发
  • 除非程序运行的慢到无法忍受的地步
  • 除非没有条件更换具有更好性能的机器的时候
  • 除非没有更好的数据结构和算法的时候
  • 再考虑使用并发
  • 不要自己实现,优先考虑使用成熟的并发库
  • 但是,你无法避免并发,必须理解它

多线程机制

CPU时间分片机制,CPU将轮流给每个任务分配其占用的时间。这个过程由线程调度器自动控制。

Java并发编程的实现

Runnable接口

定义Runnable接口的实现类,作为子线程的任务

class ARunnable implements Runnable
{
    @Override
    public void run()
    {
        // TODO
    }
}

创建Thread实例,传入任务

Thread t=new Thread(new ARunnable());
t.start();

可以使用匿名内部类或者lambda表达式进行简化

new Thread(()->{
    // TODO
}).start();

Thread类

定义Thread的派生类,重写其run方法

Thread本身就实现了Runnable接口,所以其run方法实际上是Runnable接口中的

class AThread extends Thread
{
    @Override
    public void run()
    {
        // TODO
    }
}

创建Thread实例,启动线程

Thread t = new AThread();
t.start();

与Runnable一样,也可以进行简写

new Thread(()->{
    // TODO
}).start();

Callable接口

使用Runnable定义任务时,执行完毕后不能返回任何值。如果需要在任务中返回值,可以使用Callable接口。

定义Callable接口的实现类,重写call()方法

class ACallable implements Callable<String>
{
    @Override
    public String call()
    {
        return "over";
    }
}

使用执行器Executor的submit()方法执行任务

ExecutorService executor = Executors.newCachedThreadPool();
ACallable task = new ACallable();
Future<String> future = executor.submit(task);

返回Future类型的对象,使用阻塞的get()方法获取返回值

try
{
    System.out.println(future.get());
}
catch(InterruptedException | ExecutionException e)
{
    e.printStackTrace();
}
executor.shutdown();

Fork-Join框架

Java SE7中添加了fork-join框架,专门处理可以分解为子任务的情况,如下所示

if(任务规模小于规定的值)
{
    直接处理
}
else
{
    分解为子任务;
    递归处理每一个子任务;
    合并结果;
}

使用步骤:

  • 定义任务

    如果任务有返回值,扩展RecursiveTask;如果任务没有返回值,扩展RecursiveAction。它们都是ForkJoinTask的抽象子类,重写compute()方法

  • 创建ForkJoinPool对象

  • 调用invoke()方法执行任务

  • 调用join()方法获取结果

示例:统计随机生成的double数组中,值大于0.5的数字个数

class Counter extends RecursiveTask<Integer>
{
    private static final int THRESHOLD=10000;
    private double[] nums;
    private int from;
    private int to;

    public Counter(double[] nums,int from,int to)
    {
        this.nums=nums;
        this.from=from;
        this.to=to;
    }

    @Override
    protected Integer compute()
    {
        if(to-from<THRESHOLD) // 直接运行
        {
            int count=0;
            for(int i = from;i < to;i++)
            {
                if(nums[i]>0.5)
                {
                    count++;
                }
            }
            return count;
        }
        else
        {
            //分解为子任务
            int mid=(from+to)/2;
            Counter first = new Counter(nums,from,mid);
            Counter second = new Counter(nums,mid,to);
            //递归执行子任务
            invokeAll(first,second);
            //合并结果
            return first.join()+ second.join();
        }
    }
}
ForkJoinPool pool=new ForkJoinPool();
Counter counter=new Counter(nums,0,nums.length);
pool.invoke(counter);
int count = counter.join();

Java线程生命周期与管理

线程休眠

静态的sleep()方法会抛出中断异常,必须在子线程中捕获处理,因为异常不能跨线程抛出

try
{
    //Thread.sleep(1000L);
    TimeUnit.MILLISECONDS.sleep(1000L);
}
catch(InterruptedException e)
{
    e.printStackTrace();
}

线程优先级

线程的优先级表示该线程的重要性,调度器倾向于让优先级更高的线程优先执行。然而,这种行为是不确定的。因此,不要依赖于优先级进行任何假设。

Java中线程优先级从低到高分为10个等级(1-10),默认为5

  • void setPriority(int newPriority)
  • int getPriority()

线程让步

静态的yield()方法给线程调度器一个暗示,表示当前任务完成的差不多了,可以让具有相同优先级的其它线程优先执行。
但是,线程调度器并不保证按照暗示执行,所以,不要依赖于yield()进行任何假设。

  • void yield()

后台线程

后台线程也称守护线程,用于在程序运行的过程中,在后台提供通用的服务。
当所有非后台线程结束时,程序也就终止了,同时自动杀死所有的后台线程。main线程不是后台线程。

  • void setDaemon(boolean on)
  • boolean isDaemon()

必须在线程启动之前调用setDaemon()方法。

如果是一个后台线程,那么它创建的任何线程都被自动设置为后台线程。

后台线程会在main方法终止后“突然”关闭,即使是finally代码快中的代码也不一定会被执行。

线程的加入

在线程A中调用线程B的join()方法,线程A将被挂起,等到线程B执行完毕后,线程A再从挂起的地方继续执行。join()方法可以带上一个参数,表示挂起的时间。

  • void join()
  • void join(long millis)
  • void join(long millis, int nanos)

join()方法内部使用wait()方法实现。

中断线程

调用interrupt()方法可以中断线程。

当在一个被阻塞的线程上调用interrupt()时,会抛出异常InterruptedException。

被中断的线程可以决定如何响应中断,是处理完异常后继续执行,还是中止执行。

静态的interrupted()或者非静态isInterrupted()方法用于检测当前线程的中断状态。调用前者会清除该线程的中断状态。如果捕获了中断异常,其中断状态总是返回false

  • void interrupt()
  • boolean isInterrupted()
  • boolean interrupted()

线程状态(生命周期)

Java中定义了线程的6种状态,这6种状态定义在Thread内部枚举类State中

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}
  1. 新建(NEW):当线程被new时的状态,此时它已经分配了必需的系统资源,并执行了初始化。
  2. 就绪(RUNNABLE):调用start()方法后,线程准备就绪,只要调度器分配了时间片给它,就可以开始执行任务
  3. 阻塞(BLOCKED):线程尝试获取锁时的状态
  4. 等待(WAITING):当线程调用了非计时的wait()或join()方法后,处于等待状态
  5. 计时等待(TIMED_WAITING):当先调用了sleep()或计时的wait(),join()方法后,处于计时等待状态
  6. 终止(TERMINATED):线程执行完毕或者由于未捕获的异常而终止

image

可以使用getState()方法获取线程状态,返回枚举类型的线程状态

  • State getState()

以上是关于在JAVA中并行和并发机制的区别?的主要内容,如果未能解决你的问题,请参考以下文章

那些年读过的书《Java并发编程的艺术》并发编程的挑战和并发机制的底层实现原理

[GO]并行和并发的区别

论并行,并发,同步,异步之间的联系与区别

Java并发编程(05):悲观锁和乐观锁机制

Storm篇--Storm并发机制

Storm程序的并发机制