并发专题---并发基础概念

进程VS程序
--进程是执行程序的动态过程,而程序是进程运行的静态文本。
--一个进程可以执行一个或多个程序,反之,一个程序可以被多个进程调用。
--程序是指令码,而进程是一次执行过程。
--------------------------------------------
进程通常有3个部分组成:1.程序 ,2.数据集合 ,3进程控制块(ProcessControlBlock,PCB)。

进程的程序部分描述了进程所要完成的功能。数据集合部分则有两方面的内容,及程序运行时所需的数据部分和工作区。
如果一个程序能为多个线程同时共享执行,它是进程执行时不可修改的部分。而数据集合部分则通常为一个进程独占,可修改。
程序和数据集合是进程存在的物质基础,是进程的实体。
进程控制块也称为进程描述快,它包含了进程的描述信息和控制信息,是进程动态特性的集中反映。

总之,进程基本上有自己独立的代码和数据空间,独立的程序计数器等上下文环境,进程切换的开销是较大的。

===================================

线程相关

由于进程间切换消耗比较大(需要将进程的内存切换),创建时消耗大(每个进程都有独立的数据和代码空间)于是在进程内部引入线程的概念来实现并发性。
一个进程可创建多个线程,线程之间具备并发性。不同的线程之间可以共享进程的地址空间和数据。

线程是一个程序或者进程内部的一个顺序控制流。线程本身不能独立运行,必须在进程中执行,使用进程的地址空间。每个进程有
自己单独的程序计数器,称为堆栈和本地变量。

每个程序执行时都会产生一个进程,而每个进程至少要有一个主线程。多线程就是在一个进程内有多个线程。

总之,进程内的同一类线程可以共享代码和数据空间,每个线程有独立的运行栈和程序计数器,切换的开销比较小,灵活性高。
在支持超线程和多核CPU上,多线程能够并发或者并行执行,可以在同一时段完成不同的任务,或者加快程序的执行。同一个进程内的
多个线程,调度比较灵活,可以相互协调和协作共同完成特定的任务。
==============================
创建多线程

继承Thread类或实现Runnable接口(或FutureTask类 ,其实也是实现了Runnable)

FutureTask ft= new FutureTask(new Callable<V>() {

    @Override
    public V call() throws Exception {  
 return null;
    }
       
});
    
new Thread(ft);
ft.get()//返回数据,这是用FutureTask的目的

================================
线程池

创建线程会使用相当一部分内存,其中包括有堆栈,以及每线程数据结构。如果创建过
多线程,其中每个线程都将占用一些 CPU  时间,结果将使用许多内存来支持大量线程,
每个线程都运行得很慢。这样就无法很好地使用计算资源。

Java 自从5.0 以来,提供了线程池。线程的目标执行对象可以共享线程池中有限数目的
线程对象。

例子:
100 个线程目标对象共享2 个线程

....
     //  在线程池中创建2 个线程 
    ExecutorService exec = Executors.newFixedThreadPool(2); 
    //  创建100 个线程目标对象 
    for (int index = 0; index < 100; index++) { 
         Runnable run = new Runner(index); 
          //  执行线程目标对象 
          exec.execute(run); 
    } 
    // shutdown 
    exec.shutdown(); 

....
//  线程目标对象 
class Runner implements Runnable { ... }


使用JDK 提供的线程池一般分为3 步:
1)创建线程目标对象,可以是不同的,例如程序中的Runnner;
2)使用Executors 创建线程池,返回一个ExecutorService类型的对象;
3)使用线程池执行线程目标对象,exec.execute(run),
   最后,结束线程池中的线程,exec.shutdown()。
==============================================================
线程的基本控制

1 使用Sleep 暂停执行

Thread.sleep()使当前线程的执行暂停一段指定的时间,这可以有效的使应用程序的其他
线程或者运行在计算机上的其他进程可以使用处理器时间。该方法不会放弃除CPU 之外的
其它资源。 也可指定时间,Thread.sleep(1000)。

2 使用join 等待另外一个线程结束

Join 方法让一个线程等待另一个线程的完成,如果t1,t2 是两个Thread 对象,在t1 中
调用t2.join(),会导致t1 线程暂停执行,直到t2 的线程终止。也可指定时间,如t.join(2000);

3 使用中断(Interrupt)取消线程
有三种方法可以使线程终止:
1)run()方法正常返回;2)run()方法意外结束;3)应用程序终止。

线程自己检查中断状态并终止线程比直接调用stop()放要安全很多,因为线程可以保存
自己的状态。并且stop()方法已经不推荐使用了。

和中断线程有关的方法有:
1)t.interrupt(),向线程发送中断,
2)t.isInterrupted(),测试线程是否已经被中断;
3)Thread.interrupted (),测试当前线程是否已经被中断,随后清除线程“中断”状态的静态方法。

线程的中断状态只能有线程自己清除,当线程侦测到自己被中断时,经常需要在响应中
断之前做某些清除工作,这些清除工作可能涉及那些在线程仍然保持中断状态时会受到影响
的操作。
如果被中断的线程正在执行sleep,或者wait 方法,就会抛出InterruptedException 异常。
这种抛出异常的中断会清除线程的中断状态。

4 使用Stop 终止线程

该方法具有固有的不安全性(现在已经过时了)。用 Thread.stop  来终止线程将释放它已经锁定的所有监视
器(作为沿堆栈向上传播的未检查 ThreadDeath 异常的一个自然后果)。如果以前受这些监
视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能
导致任意的行为。

你可能感兴趣的:(并发)