学习笔记(九)并发(一)

《Java编程思想》整理的一些学习笔记,有不对的地方,欢迎指出。

1.对象技术提供了一种把程序划分成若干独立部分的方式。通常,还需要把程序转换成彼此分离的,能独立运行的子任务。每个独立子任务被称为一个“线程”。而进程,是一个自包含的运行程序,它有自己的地址空间。操作系统通过周期性的将CPU分配到不同的任务,使其能够同时运行不止一个进程,而每个进程都像是连续运行,一气呵成的。线程是进程内部的一个控制序列流。所以一个进程可以具有多个并发执行的线程。

2.使用并发的最引人注目的理由之一就是,产生一个可作出响应的用户界面。我们希望程序需要一边连续进行计算,同时还要把控制权交给用户界面,这样程序才能响应用户的操作。例如:如果你有一个“退出”按钮,你一定不希望在程序的每段代码里都检测按钮的状态,但你还是希望对这个按钮能够作出响应,就好像你定期对其进行检测一样。即好像让CPU同时出现在两个地方,传统方法解决不了,这时候就要用到并发。

3.并发还可以用来优化程序的吞吐量。比如在等待数据到达输入/输出端口的同时,可以进行其他重要的工作。若是不使用线程,唯一可行的就是不断的查询输入/输出端口,这种方法不仅笨拙,而且很困难。另外注意,具有多个线程的程序,必须也能够在只有单CPU的机器上运行。

4.写一个线程最简单的做法就是从java.lang.Thread继承,Thread最重要的方法是run(),我们要覆盖这个方法,以达到我们的目的。这样run()里的代码就能够与程序里的其他线程“同时”运行。

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:


 class PrimeRun implements Runnable {
     long minPrime;
     PrimeRun(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }


然后,下列代码会创建并启动一个线程:

 PrimeRun p = new PrimeRun(143);
 new Thread(p).start();

每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。

5.Tread对象的run()方法事实上总会有某种形式的循环,使得线程一直运行下去知道不再需要,所以要设定跳出循环的条件。通常,run()被写成无限循环的形式,这就意味着,除非有某个条件使得run()终止,否则它将永远运行下去。

6.Tread类的start()方法将为线程执行特殊的初始化操作,然后自动调用run()方法。所以整个步骤是:首先调用构造器来构造对象,在构造器中调用了start()方法来配置线程,然后有线程执行机制调用run()。如果不调用start(),线程永远不会启动(也可以不必在构造器中调用)。

7.因为线程调用机制的行为是不确定的,所以每次运行程序都会产生不同的输出结果,JDK版本低的可能会先执行完线程1才会执行下一线程,JDK1.4以后,调度器采用更合适的时间切片行为,可以使得线程可以穿插执行。

8.当在main()函数中创建若干个Thread对象的时候,并没有获得它们中任何一个的引用,给个例子:

public class Demo extends Thread{

    private int countDown = 5;
    private static int threadCount = 0;

    public Demo(){
        super(""+ ++threadCount);              // 调用Tread构造器,给线程对象指定一个名字
        start();
    }

    public String toString(){
        return "#"+getName()+":"+ countDown;  //  使用getName()方法获取线程的名字
    }

    public void run(){
        while(true){
            System.out.println(this);
            if(--countDown == 0)
                return;
        }
    }

    public static void main(String[] args){

        for(int i = 0; i < 5; i++){
            new Demo();
        }
    }
}

就像上述的例子中,只是创建了对象没有对应的引用。对于普通的对象而言,这会使它成为垃圾回收器要回收的目标,但对于Thread对象就不会了。每个Thread对象都需要“注册”自己,所以实际上在某个地方存在着对它的引用,垃圾回收器只有在线程离开了run()并且死亡之后才能把它清理掉。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 10:03:36

学习笔记(九)并发(一)的相关文章

APUE 学习笔记(九) 高级I/O

1. 非阻塞I/O 低速系统调用时可能会使进程永远阻塞的一类系统调用,包括以下调用: (1)某些文件类型你(网络socket套接字.终端设备.管道)暂无可使用数据,则读操作可能会使调用者永远阻塞 (2)如果数据不能立即被(1)中文件类型接受,则写操作会使调用者永远阻塞 (3)某些进程间通信函数 非阻塞I/O使我们可以调用open.read.write这样的I/O操作,并使这些操作不会永远阻塞,如果这种操作不能完成,则调用立即出错返回 对于一个给定的文件有两种方法对其指定非阻塞I/O: (1)调用

python学习笔记九——文件与目录

1.python进行文件读写的函数是open或file类 mode:r  只读 r+   读写 w  写入,先删除原文件,再重新写入,如果文件没有则创建 w+  读写,先删除原文件,再重新写入,如果文件没有则创建(可写入和输出) a  写入,在文件末尾追加新的内容,文件不存在则创建 a+  读写,在文件末尾追加新的内容,文件不存在则创建 b  打开二进制文件,可与r,w,a,+结合使用 U  支持所有的换行符号,"\r","\n","\r\n"

angular学习笔记(九)-css类和样式3

再来看一个选择li列表的例子: 点击li中的任意项,被点击的li高亮显示: <!DOCTYPE html> <html ng-app> <head> <title>6.3css类和样式</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="scri

angular学习笔记(九)-css类和样式2

在上一个例子中,元素的类名使用拼接的方法,这样,类名中就不得不带有true或false,并且不易维护,所以,angular使用ng-class属性来控制元素的类名: 我们来看一个小例子,点击error按钮,顶部提示错误框,点击warning按钮,顶部提示警告框. 错误框的类名是.err,警告框的类名是.warn: <!DOCTYPE html> <html ng-app> <head> <title>6.2css类和样式</title> <

Linux System Programming 学习笔记(九) 内存管理

1. 进程地址空间 Linux中,进程并不是直接操作物理内存地址,而是每个进程关联一个虚拟地址空间 内存页是memory management unit (MMU) 可以管理的最小地址单元 机器的体系结构决定了内存页大小,32位系统通常是 4KB, 64位系统通常是 8KB 内存页分为 valid or invalid: A valid page is associated with an actual page of data,例如RAM或者磁盘上的文件 An invalid page is

虚拟机VMWare学习笔记九 - 物理机上的文件挂载到虚拟机上

物理机上的文件夹或盘符直接挂载到虚拟机上使用. VM -- Settings Options -- Shared Folders -- 勾选Always enabled , 勾选Map as a network drive in Windows guests 在点击下面的添加来添加共享的文件夹 选择路径 可以看到虚拟机中的共享文件夹已经出现在Windows 中了 虚拟机VMWare学习笔记九 - 物理机上的文件挂载到虚拟机上

linux网络编程学习笔记之五 -----并发机制与线程?

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.能够在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理须要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也非常easy,在主线程中定时,定

linux网络编程学习笔记之五 -----并发机制与线程池

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我只是举几个例子作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.可以在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理需要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也很简单,在主线程中定时,定时到期,

初探swift语言的学习笔记九(OC与Swift混编)

swift 语言出来后,可能新的项目直接使用swift来开发,但可能在过程中会遇到一些情况,某些已用OC写好的类或封装好的模块,不想再在swift 中再写一次,哪就使用混编.这个在IOS8中是允许的. 先中简单的入手,先研究在同一个工程目录下混合使用的情况. 为了演示.先准备两个类 第一个是swift语言写的类,文件名为 act.swift import Foundation class Act : NSObject { func hasAct(tag:Int) -> String { swit

《Hibernate学习笔记九》:多对一和一对多的关联关系

<Hibernate学习笔记九>:多对一和一对多的关联关系 前面介绍了一对一的关联关系在Hibernate应该如何来实现,这篇博文就来介绍下多对一和一对多的关联关系. 多对一和一对多的关联关系在我们的生活中也比较常见,例如,在我们学生时代,一个班级可以有多个学生,而一个学生只能属于一个班级,这就是一个多对一(一对多)的例子: 还有在我们的工作中,一个工作小组可以有多个用户,而一个用户只能属于一个小组,这也是一个多对一(一对多)的关系的例子. 1.多对一的单向关联关系 下面就以一个工作小组可以有