当前位置: 首页 > news >正文

wordpress建站博客园微信做淘宝客 网站打不开了

wordpress建站博客园,微信做淘宝客 网站打不开了,网站建设公司发展建议,做影视网站 片源从哪里来本文是Oracle官方的Java并发相关的教程#xff0c;感谢并发编程网的翻译和投递。计算机的使用者一直以为他们的计算机可以同时做很多事情。他们认为当其他的应用程序在下载文件#xff0c;管理打印队列或者缓冲音频的时候他们可以继续在文字处理程序上工作。甚至对于单个应用…本文是Oracle官方的Java并发相关的教程感谢并发编程网的翻译和投递。计算机的使用者一直以为他们的计算机可以同时做很多事情。他们认为当其他的应用程序在下载文件管理打印队列或者缓冲音频的时候他们可以继续在文字处理程序上工作。甚至对于单个应用程序他们任然期待它能在在同一时间做很多事情。举个例子一个流媒体播放程序必须能同时完成以下工作从网络上读取数字音频解压缩数字音频管理播放和更新程序显示。甚至文字处理器也应该能在忙于重新格式化文本和刷新显示的情况下同时响应键盘和鼠标事件。这样的软件就被称为并发软件。通过Java语言和Java类库对于基础并发的支持Java平台具有完全(from the ground up )支持并发编程的能力。从JDK5.0起Java平台还引入了高级并发APIs。这个课程不仅涵盖了Java平台基础并发内容还对高级并发APIs有一定的阐述。进程和线程(本部分原文链接译文链接译者bjsuo校对郑旭东)在并发编程中有两个基本的执行单元进程和线程。在java语言中并发编程最关心的是线程然而进程也是非常重要的。即使在只有单一的执行核心的计算机系统中也有许多活动的进程和线程。因此在任何给定的时刻只有一个线程在实际执行。处理器的处理时间是通过操作系统的时间片在进程和线程中共享的。现在具有多处理器或有多个执行内核的多处理器的计算机系统越来越普遍这大大增强了系统并发执行的进程和线程的吞吐量–但在不没有多个处理器或执行内核的简单的系统中并发任然是可能的。进程进程具有一个独立的执行环境。通常情况下进程拥有一个完整的、私有的基本运行资源集合。特别地每个进程都有自己的内存空间。进程往往被看作是程序或应用的代名词然而用户看到的一个单独的应用程序实际上可能是一组相互协作的进程集合。为了便于进程之间的通信大多数操作系统都支持进程间通信(IPC)如pipes 和sockets。IPC不仅支持同一系统上的通信也支持不同的系统。Java虚拟机的大多数实现是单进程的。Java应用可以使用的ProcessBuilder对象创建额外的进程多进程应用超出了本课的范围。线程线程有时也被称为轻量级的进程。进程和线程都提供了一个执行环境但创建一个新的线程比创建一个新的进程需要的资源要少。线程是在进程中存在的 — 每个进程最少有一个线程。线程共享进程的资源包括内存和打开的文件。这样提高了效率但潜在的问题就是线程间的通信。多线程的执行是Java平台的一个基本特征。每个应用都至少有一个线程 – 或几个如果算上“系统”线程的话比如内存管理和信号处理等。但是从程序员的角度来看启动的只有一个线程叫主线程。这个线程有能力创建额外的线程我们将在下一节演示。线程对象(本部分原文链接译文链接译者郑旭东)在Java中每个线程都是Thread类的实例。并发应用中一般有两种不同的线程创建策略。直接控制线程的创建和管理每当应用程序需要执行一个异步任务的时候就为其创建一个线程将线程的管理从应用程序中抽象出来作为执行器应用程序将任务传递给执行器有执行器负责执行。这一节我们将讨论Thread对象有关Executors将在高级并发对象一节中讨论。定义并启动一个线程应用程序在创建一个线程实例时必须提供需要在线程中运行的代码。有两种方式去做到这一点提供一个Runnable对象。Runnable对象仅包含一个run()方法在这个方法中定义的代码将在会线程中执行。将Runnable对象传递给Thread类的构造函数即可如下面这个HelloRunnable的例子1 public class HelloRunnable implementsRunnable {23 public voidrun() {4 System.out.println(Hello from a thread!);5 }67 public static voidmain(String args[]) {8 (new Thread(newHelloRunnable())).start();9 }1011 }View Code继承Thread类。Thread类自身已实现了Runnable接口但它的run()方法中并没有定义任何代码。应用程序可以继承与Thread类并复写run()方法。如例子HelloThreadpublic class HelloThread extendsThread {public voidrun() {System.out.println(Hello from a thread!);}public static voidmain(String args[]) {(newHelloThread()).start();}}View Code需要注意的是上述两个例子都需要调用Thread.start()方法来启动一个新的线程。 哪一种方式是我们应该使用的相对来说第一种更加通用因为Runnable对象可以继承于其他类(Java只支持单继承当一个类继承与Thread类后就无法继承与其他类)。第二种方法更易于在简单的应用程序中使用但它的局限就是你的任务类必须是Thread的子类。这个课程更加聚焦于第一种将Runnable任务和Thread类分离的方式。不仅仅是因为这种方式更加灵活更因为它更适合后面将要介绍的高级线程管理API。 Thread类定义了一些对线程管理十分有用的的方法。在这些方法中有一些静态方法可以给当前线程调用它们可以提供一些有关线程的信息或者影响线程的状态。而其他一些方法可以由其他线程进行调用用于管理线程和Thread对象。我们将在下面的章节中深入探讨这些内容。使用Sleep方法暂停一个线程使用Thread.sleep()方法可以暂停当前线程一段时间。这是一种使处理器时间可以被其他线程或者运用程序使用的有效方式。sleep()方法还可以用于调整线程执行节奏(见下面的例子)和等待其他有执行时间需求的线程(这个例子将在下一节演示)。在Thread中有两个不同的sleep()方法一个使用毫秒表示休眠的时间而另一个是用纳秒。由于操作系统的限制休眠时间并不能保证十分精确。休眠周期可以被interrups所终止我们将在后面看到这样的例子。不管在任何情况下我们都不应该假定调用了sleep()方法就可以将一个线程暂停一个十分精确的时间周期。SleepMessages程序为我们展示了使用sleep()方法每四秒打印一个信息的例子public classSleepMessages {public static voidmain(String args[])throwsInterruptedException {String importantInfo[]{Mares eat oats,Does eat oats,Little lambs eat ivy,A kid will eat ivy too};for (int i 0;ii) {//Pause for 4 secondsThread.sleep(4000);//Print a messageSystem.out.println(importantInfo[i]);}}}View Codemain()方法声明了它有可能抛出InterruptedException。当其他线程中断当前线程时sleep()方法就会抛出该异常。由于这个应用程序并没有定义其他的线程所以并不用关心如何处理该异常。中断(Interrupts)中断是给线程的一个指示告诉它应该停止正在做的事并去做其他事情。一个线程究竟要怎么响应中断请求取决于程序员不过让其终止是很普遍的做法。这是本文重点强调的用法。一个线程通过调用对被中断线程的Thread对象的interrupt()方法发送中断信号。为了让中断机制正常工作被中断的线程必须支持它自己的中断(即要自己处理中断)中断支持线程如何支持自身的中断这取决于它当前正在做什么。如果线程正在频繁调用会抛InterruptedException异常的方法在捕获异常之后它只是从run()方法中返回。例如假设在SleepMessages的例子中关键的消息循环在线程的Runnable对象的run方法中代码可能会被修改成下面这样以支持中断for (int i 0; i importantInfo.length; i) {//Pause for 4 secondstry{Thread.sleep(4000);}catch(InterruptedException e) {//Weve been interrupted: no more messages.return;}//Print a messageSystem.out.println(importantInfo[i]);}View Code许多会抛InterruptedException异常的方法(如sleep())被设计成接收到中断后取消它们当前的操作并在立即返回。如果一个线程长时间运行而不调用会抛InterruptedException异常的方法会怎样 那它必须周期性地调用Thread.interrupted()方法该方法在接收到中断请求后返回true。例如for (int i 0; i inputs.length; i) {heavyCrunch(inputs[i]);if(Thread.interrupted()) {//Weve been interrupted: no more crunching.return;}}View Code在这个简单的例子中代码只是检测中断并在收到中断后退出线程。在更复杂的应用中抛出一个InterruptedException异常可能更有意义。if(Thread.interrupted()){throw newInterruptedException();}View Code这使得中断处理代码能集中在catch语句中。中断状态标记中断机制通过使用称为中断状态的内部标记来实现。调用Thread.interrupt()设置这个标记。当线程通过调用静态方法Thread.interrupted()检测中断时中断状态会被清除。非静态的isInterrupted()方法被线程用来检测其他线程的中断状态不改变中断状态标记。按照惯例任何通过抛出一个InterruptedException异常退出的方法当抛该异常时会清除中断状态。不过通过其他的线程调用interrupt()方法中断状态总是有可能会立即被重新设置。JoinsJoin()方法可以让一个线程等待另一个线程执行完成。若t是一个正在执行的Thread对象t.join();将会使当前线程暂停执行并等待t执行完成。重载的join()方法可以让开发者自定义等待周期。然而和sleep()方法一样join()方法依赖于操作系统的时间处理机制你不能假定join()方法将会精确的等待你所定义的时长。如同sleep()方法join()方法响应中断并在中断时抛出InterruptedException。一个简单的线程例子下面这个简单的例子将会把这一节的一些概念放到一起演示。SimpleThreads程序有两个线程组成第一个是主线程它从创建了一个线程并等待它执行完成。如果MessageLoop线程执行了太长时间主线程将会将其中断。MessageLoop现场将会打印一系列的信息。如果中断在它打印完所有信息前发生它将会打印一个特定的消息并退出。public classSimpleThreads {//Display a message, preceded by//the name of the current threadstatic voidthreadMessage(String message) {String threadNameThread.currentThread().getName();System.out.format(%s: %s%n,threadName,message);}private static classMessageLoopimplementsRunnable {public voidrun() {String importantInfo[]{Mares eat oats,Does eat oats,Little lambs eat ivy,A kid will eat ivy too};try{for (int i 0;ii) {//Pause for 4 secondsThread.sleep(4000);//Print a messagethreadMessage(importantInfo[i]);}}catch(InterruptedException e) {threadMessage(I wasnt done!);}}}public static voidmain(String args[])throwsInterruptedException {//Delay, in milliseconds before//we interrupt MessageLoop//thread (default one hour).long patience 1000 * 60 * 60;//If command line argument//present, gives patience//in seconds.if (args.length 0) {try{patience Long.parseLong(args[0]) * 1000;}catch(NumberFormatException e) {System.err.println(Argument must be an integer.);System.exit(1);}}threadMessage(Starting MessageLoop thread);long startTime System.currentTimeMillis();Thread t new Thread(newMessageLoop());t.start();threadMessage(Waiting for MessageLoop thread to finish);//loop until MessageLoop//thread exitswhile(t.isAlive()) {threadMessage(Still waiting...);//Wait maximum of 1 second//for MessageLoop thread//to finish.t.join(1000);if (((System.currentTimeMillis() - startTime) patience)t.isAlive()) {threadMessage(Tired of waiting!);t.interrupt();//Shouldnt be long now//-- wait indefinitelyt.join();}}threadMessage(Finally!);}}同步(本部分原文链接译文链接译者蘑菇街-小宝Greenster李任校对丁一郑旭东李任)线程间的通信主要是通过共享域和引用相同的对象。这种通信方式非常高效不过可能会引发两种错误线程干扰和内存一致性错误。防止这些错误发生的方法是同步。不过同步会引起线程竞争当两个或多个线程试图同时访问相同的资源随之就导致Java运行时环境执行其中一个或多个线程比原先慢很多甚至执行被挂起这就出现了线程竞争。线程饥饿和活锁都属于线程竞争的范畴。关于线程竞争的更多信息可参考活跃度一节。本节内容包括以下这些主题线程干扰讨论了当多个线程访问共享数据时错误是怎么发生的。内存一致性错误讨论了不一致的共享内存视图导致的错误。同步方法讨论了 一种能有效防止线程干扰和内存一致性错误的常见做法。内部锁和同步讨论了更通用的同步方法以及同步是如何基于内部锁实现的。原子访问讨论了不能被其他线程干扰的操作的总体思路。1.  线程干扰下面这个简单的Counter类classCounter {private int c 0;public voidincrement() {c;}public voiddecrement() {c--;}public intvalue() {returnc;}}Counter类被设计成每次调用increment()方法c的值加1每次调用decrement()方法c的值减1。如果当同一个Counter对象被多个线程引用线程间的干扰可能会使结果同我们预期的不一致。当两个运行在不同的线程中却作用在相同的数据上的操作交替执行时就发生了线程干扰。这意味着这两个操作都由多个步骤组成而步骤间的顺序产生了重叠。Counter类实例的操作会交替执行这看起来似乎不太可能因为c上的这两个操作都是单一而简单的语句。然而即使一个简单的语句也会被虚拟机转换成多个步骤。我们不去深究虚拟机内部的详细执行步骤——理解c这个单一的语句会被分解成3个步骤就足够了获取当前c的值对获取到的值加1把递增后的值写回到c语句c–也可以按同样的方式分解除了第二步的操作是递减而不是递增。假设线程A调用increment()的同时线程B调用decrement().如果c的初始值为0线程A和B之间的交替执行顺序可能是下面这样线程A获取c线程B获取c线程A对获取的值加1结果为1线程B对获取的值减1结果为-1线程A结果写回到c,c现在是1线程B结果写回到c,c现在是-1线程A的结果因为被线程B覆盖而丢失了。这个交替执行的结果只是其中一种可能性。在不同的环境下可能是线程B的结果丢失了也可能是不会出任何问题。由于结果是不可预知的所以线程干扰的bug很难检测和修复。2.  内存一致性错误当不同的线程对相同的数据产生不一致的视图时会发生内存一致性错误。内存一致性错误的原因比较复杂也超出了本教程的范围。不过幸运的是一个程序员并不需要对这些原因有详细的了解。所需要的是避免它们的策略。避免内存一致性错误的关键是理解happens-before关系。这种关系只是确保一个特定语句的写内存操作对另外一个特定的语句可见。要说明这个问题请参考下面的例子。假设定义和初始化了一个简单int字段int counter 0 ;这个counter字段被AB两个线程共享。假设线程A对counter执行递增:counter;然后很快的线程B输出counter:System.out.println(counter);如果这两个语句已经在同一个线程中被执行过那么输出的值应该是“1”。不过如果这两个语句在不同的线程中分开执行那输出的值很可能是“0”因为无法保证线程A对counter的改动对线程B是可见的——除非我们在这两个语句之间已经建立了happens-before关系。有许多操作会建立happens-before关系。其中一个是同步我们将在下面的章节中看到。我们已经见过两个建立happens-before关系的操作。当一条语句调用Thread.start方法时和该语句有happens-before关系的每一条语句跟新线程执行的每一条语句同样有happens-before关系。创建新线程之前的代码的执行结果对线新线程是可见的。当一个线程终止并且当导致另一个线程中Thread.join返回时被终止的线程执行的所有语句和在join返回成功之后的所有语句间有happens-before关系。线程中代码的执行结果对执行join操作的线程是可见的。要查看建立happens-before关系的操作列表请参阅java.util.concurrent包的摘要页面。3.  同步方法Java编程语言提供两种同步方式同步方法和同步语句。相对较复杂的同步语句将在下一节中介绍。本节主要关注同步方法。要让一个方法成为同步方法只需要在方法声明中加上synchronized关键字public classSynchronizedCounter {private int c 0;public synchronized voidincrement() {c;}public synchronized voiddecrement() {c--;}public synchronized intvalue() {returnc;}}如果count是SynchronizedCounter类的实例那么让这些方法成为同步方法有两个作用:首先相同对象上的同步方法的两次调用它们要交替执行是不可能的。 当一个线程正在执行对象的同步方法时所有其他调用该对象同步方法的线程会被阻塞(挂起执行),直到第一个线程处理完该对象。其次当一个同步方法退出时它会自动跟该对象同步方法的任意后续调用建立起一种happens-before关系。这确保对象状态的改变对所有线程是可见的。注意构造方法不能是同步的——构造方法加synchronized关键字会报语法错误。同步的构造方法没有意义因为当这个对象被创建的时候只有创建对象的线程能访问它。警告当创建的对象会被多个线程共享时必须非常小心对象的引用不要过早“暴露”出去。比如假设你要维护一个叫instances的List它包含类的每一个实例对象。你可能会尝试在构造方法中加这样一行instances.add(this);不过其他线程就能够在对象构造完成之前使用instances访问对象。同步(synchronized)方法使用一种简单的策略来防止线程干扰和内存一致性错误如果一个对象对多个线程可见对象域上的所有读写操作都是通过synchronized方法来完成的。(一个重要的例外final域在对象被创建后不可修改,能被非synchronized方法安全的读取)。synchronized同步策略很有效不过会引起活跃度问题我们将在本节后面看到。4.  内部锁与同步同步机制的建立是基于其内部一个叫内部锁或者监视锁的实体。(在Java API规范中通常被称为监视器。)内部锁在同步机制中起到两方面的作用对一个对象的排他性访问建立一种happens-before关系而这种关系正是可见性问题的关键所在。每个对象都有一个与之关联的内部锁。通常当一个线程需要排他性的访问一个对象的域时首先需要请求该对象的内部锁当访问结束时释放内部锁。在线程获得内部锁到释放内部锁的这段时间里我们说线程拥有这个内部锁。那么当一个线程拥有一个内部锁时其他线程将无法获得该内部锁。其他线程如果去尝试获得该内部锁则会被阻塞。当线程释放一个内部锁时该操作和对该锁的后续请求间将建立happens-before关系。5.  同步方法中的锁当线程调用一个同步方法时它会自动请求该方法所在对象的内部锁。当方法返回结束时则自动释放该内部锁即使退出是由于发生了未捕获的异常内部锁也会被释放。你可能会问调用一个静态的同步方法会如何由于静态方法是和类(而不是对象)相关的所以线程会请求类对象(Class Object)的内部锁。因此用来控制类的静态域访问的锁不同于控制对象访问的锁。6.  同步块另外一种同步的方法是使用同步块。和同步方法不同同步块必须指定所请求的是哪个对象的内部锁public voidaddName(String name) {synchronized(this) {lastNamename;nameCount;}nameList.add(name);}在上面的例子中addName方法需要使lastName和nameCount的更改保持同步而且要避免同步调用该对象的其他方法。(在同步代码中调用其他方法会产生Liveness一节所描述的问题。)如果不使用同步块那么必须要定义一个额外的非同步方法而这个方法仅仅是用来调用nameList.add。使用同步块对于更细粒度的同步很有帮助。例如类MsLunch有两个实例域c1和c2他们并不会同时使用(译者注即c1和c2是彼此无关的两个域)所有对这两个域的更新都需要同步但是完全不需要防止c1的修改和c2的修改相互之间干扰(这样做只会产生不必要的阻塞而降低了并发性)。这种情况下不必使用同步方法可以使用和this对象相关的锁。这里我们创建了两个“锁”对象(译者注起到加锁效果的普通对象lock1和lock2)。public classMsLunch {private long c1 0;private long c2 0;private Object lock1 newObject();private Object lock2 newObject();public voidinc1() {synchronized(lock1) {c1;}}public voidinc2() {synchronized(lock2) {c2;}}}使用这种方法时要特别小心需要十分确定c1和c2是彼此无关的域。7.  可重入同步还记得吗一个线程不能获得其他线程所拥有的锁。但是它可以获得自己已经拥有的锁。允许一个线程多次获得同一个锁实现了可重入同步。这里描述了一种同步代码的场景直接的或间接地调用了一个也拥有同步代码的方法且两边的代码使用的是同一把锁。如果没有这种可重入的同步机制同步代码则需要采取许多额外的预防措施以防止线程阻塞自己。8.  原子访问在编程过程中原子操作是指所有操作都同时发生。原子操作不能被中途打断要么全做要么不做。原子操作在完成前不会有看得见的副作用。我们发现像c这样的增量表达式并没有描述原子操作。即使是非常简单的表达式也能够定义成能被分解为其他操作的复杂操作。然而有些操作你可以定义为原子的对引用变量和大部分基本类型变量(除long和double之外)的读写是原子的。对所有声明为volatile的变量(包括long和double变量)的读写是原子的。原子操作不会交错于是可以放心使用不必担心线程干扰。然而这并不能完全消除原子操作上的同步因为内存一致性错误仍可能发生。使用volatile变量可以降低内存一致性错误的风险因为对volatile变量的任意写操作对于后续在该变量上的读操作建立了happens-before关系。这意味着volatile变量的修改对于其他线程总是可见的。更重要的是这同时也意味着当一个线程读取一个volatile变量时它不仅能看到该变量最新的修改而且也能看到致使该改变发生的代码的副效应。使用简单的原子变量访问比通过同步代码来访问更高效但是需要程序员更加谨慎以避免内存一致性错误。至于这额外的付出是否值得得看应用的大小和复杂度。java.util.concurrent包中的一些类提供了一些不依赖同步机制的原子方法。我们将在高级并发对象这一节中讨论它们。活跃度
http://www.pierceye.com/news/180351/

相关文章:

  • 哪家网站建设好大连房产网
  • 企业做推广哪些网站比较好兰州有做百度网站的吗
  • 网站建设和管理规则自己建网站的流程
  • 网站的前期推广广州网站建设加盟
  • 网站灰色 代码深圳的深圳的网站建设公司
  • 做电影采集网站需要多大vps安徽建设新工程信息网站
  • 中小企业网站制作化工厂网站建设
  • 电子政务网站建设出版社百度网页提交入口
  • 专业柳州网站建设哪家便宜淄博桓台网站建设定制
  • 网站建设投标标书企业网站建设销售前景
  • wordpress建站教程凌风wordpress 仪表盘 慢
  • 怎样给网站或者商品做推广关于建网站新闻
  • 上海 微信网站 建站一对一直播app
  • ppt模板免费下载网站哪个好克拉玛依市住房和建设局网站
  • 制作网站得多少钱交互设计留学
  • 理财网站免费建设经典重庆新闻论坛
  • 南京专业网站制作哪家好企业所得税交多少
  • 广西网站建设哪家好常熟做网站的
  • 礼品网站制作辽宁省建设部网站
  • 网站群的建设目标澧县网页设计
  • 邯郸网站建设在哪里网站建设yingkagou
  • 姜堰区网站建设企业公司网站制作
  • 目前做的比较好的法律网站有哪些兰州seo技术优化排名公司
  • wordpress网站接入qqwordpress调用二级分类目录
  • 自建站有哪些站点soho 网站建设
  • cms网站建设如果在网上接网站建设项目
  • 建设网站的重点与难点在于社区网站模版
  • 自己在线制作logo免费网站公司网页设计教程
  • 广西城乡建设网站一家企业如何做网站推广
  • 小程序可以做网站吗wordpress 活动插件