探讨Java中的多线程概念 - foojay


解释Java编程语言中多线程的复杂性,让我们从快速概览和理解核心概念开始。
 
操作系统中的线程概念

  • 线程:线程是轻量级进程,但它在多个方面与进程不同。线程的主要特征是它创建并发执行过程的感觉。它可以有效地分配工作并执行单个任务,可以用于调度和异步执行任务,它具有比进程更有效的上下文切换机制,并且它与其他线程共享内存空间,但是可以拥有自己的存储空间
  • 关键部分Critical Section:代码的关键部分被标识为焦点区域,多个线程可以同时访问该焦点区域并可以修改状态。由于共享资源时会同时进行修改,因此需要对访问进行控制。
  • 信号量:信号量是一种资源计数,可用于控制对共享资源的访问,尤其是在多线程环境中。
  • 互斥量:互斥量是一种同步结构,仅允许一个线程一次使用资源并拥有与之相关的所有权。
  • 监控器:一种同步构造,它允许相互排斥并具有等待条件为真的能力。
  • 死锁:在访问代码的关键部分时,可能存在多个线程访问多个共享资源的情况。在这种情况下,当单个线程需要访问共享资源时,它可能首先需要释放当前持有的共享资源。关于同一资源的另一个同时执行的线程也可能是正确的。当无法实现这种互斥时,将导致死锁。
  • 死锁预防:防止死锁情况发生的技术构成了死锁预防。
  • 死锁处理:死锁的检测及其消除构成了死锁处理。
  • 重入:在不完成其先前调用的情况下可以重新输入方法或子例程的情况。 

 
Java中线程接口或类

  • 线程:解释了线程类的重要方法,并在代码示例中显示了用法。即使是有经验的Java程序员在多线程中,最令人困惑和常见的错误是理解锁。在每种方法中,我都提供了共享对象上的锁定状态。
  • Runnable:创建线程的另一种方法是实现此接口。可以通过实现Runnable接口或扩展Thread类来在Java中创建线程。程序员将必须重写此接口中的run()方法以实现逻辑。
  • start(),会获取锁定状态;这是用来调度线程运行的方法。一旦计划好并且CPU周期可用,该线程就会实际运行。
  • run(),会获取锁定;Thread运行时会隐式调用它以开始执行线程。
  • yield(),锁定保持;此方法将控制权产生或转移给具有相同优先级的另一个线程。它不能保证将控制权转移到哪个线程,也不能保证。下面的代码片段还显示了如何通过扩展Thread类来创建Thread。
  • sleep(),锁定会保持;此方法使当前正在执行的线程在给定的时间段内暂停执行。时间段以毫秒为单位指定。它抛出一个中断的异常,该异常需要由程序员处理。
  • join(),锁定会保持;这导致执行模式,其中所有线程都在当前线程的末尾加入。换句话说,当前线程在切换到另一个线程之前已完成。它将引发一个中断的异常,程序员必须处理该异常。
  • suspend(),已弃用。
  • resume(),已弃用;不建议使用这些线程方法,因为它可能导致死锁和冻结进程。当必须恢复挂起线程的线程需要在调用resume()之前访问该挂起线程持有的共享资源或锁时,尤其如此。
  • stop(),已弃用;不建议使用此线程方法,因为由于损坏的对象而产生的状态不一致。我不提供代码示例,因为它是非常直接的用法–但即使使用非常旧的编译器版本,我也不建议使用这些方法。

 
Java中的对象
Java中的Object类固有地包含可以控制对此对象的访问的方法,尤其是在共享或多线程应用程序中。
  • wait(),当前对象锁定已释放,已持有其他锁定;wait()方法使当前线程暂停执行并进入等待状态。它还释放它在当前对象上持有的锁,但保留其他对象上的所有其他锁。
  • notify(),任意等待线程处于锁定状态;notify()方法通知正在等待获取当前共享对象上的锁的任意线程。
  • notifyAll(),任意等待的线程正在锁定状态;此方法的notifyAll()对应对象通知所有正在等待获取共享库上的锁的线程。
  • 关于锁的注意事项:每当您想到Java中的锁或监视器时,都可以使用此原则:线程进行的任何并发修改都不应导致对象损坏。唯一的例外是wait()和notify()机制,它们可能导致交换或切换控制之前更改共享资源或对象。损坏的对象是指状态发生不希望的或可破坏的更改的对象。
  • 同步synchronized:在Java中,sync关键字用于控制对代码关键部分的访问。另外,它是Java中的线程监视器的实现。sync关键字既可以应用于静态方法,也可以应用于实例级方法或块。当线程进入同步的块或方法时,它将获得对该类或对象的锁定。对于静态同步方法,单个锁保存在类级别,并且不同于每个类实例保存的实例级锁。sync关键字在共享资源上提供了必要的互斥。只能在同步块或方法中调用wait(),notify()和notifyAll()。Java不固有地支持互斥对象。

案例研究:设计一个多线程系统,该系统的共享资源只能采用两个值。0或1。它应该有两种方法,一种用于递增和递减的方法,由两个线程同时调用。其中一个线程只能不断增加,而另一个只能不断减少。它们的操作应互斥。
解决方案:它是生产者-消费者问题的简化版本:

package org.csi_india.programming.workbench.multithreading;

public class CSIDecrementer implements Runnable {

  CSISharedObject csiSharedObject;

  CSIDecrementer(CSISharedObject csiSharedObject) {
    this.csiSharedObject=csiSharedObject;
  }

  public void run() {
    while(true) csiSharedObject.decrementerAccess();
  }

}
package org.csi_india.programming.workbench.multithreading;

public class CSIIncrementer implements Runnable {

  CSISharedObject csiSharedObject;

  CSIIncrementer(CSISharedObject csiSharedObject) {
    this.csiSharedObject=csiSharedObject;
  }

  public void run() {
    while(true) csiSharedObject.incrementerAccess();
  }

}
package org.csi_india.programming.workbench.multithreading;

public class CSIWorkbench extends Thread {

  public static void main(String args) {
    CSISharedObject csiShared=new CSISharedObject();
    Thread csiThread01=new Thread(new CSIIncrementer(csiShared));
    csiThread01.start();
    Thread csiThread02=new Thread(new CSIDecrementer(csiShared));
    csiThread02.start();
  }

}
package org.csi_india.programming.workbench.multithreading;

public class CSISharedObject {
   // access from within this class only
   private int;
   public synchronized void decrementerAccess() {
   try {
     if (x = ) {
       x--;
       notify();
     } else {
       wait();
     }
   } catch (InterruptedException e) {
       System.out.println(
"thread interrupted");
   }
}

public synchronized void incrementerAccess() {
   try {
     if (x = ) {
     x++;
     notify();
      } else {
        wait();
      }
   } catch (InterruptedException e) {
      System.out.println(
"thread interrupted");
   }
}

 

以下是为Java中的异步任务执行提供了更细化或受控的访问。

  • Callable:类似于Runnable的另一个类,其实例可能由另一个线程执行。
  • Executors:用于创建线程池的帮助程序接口。
  • ExecutorService:异步任务执行器,可用于提交Runnable或Callable任务以执行,然后通过Future对象跟踪它们的状态。
  • Future:对象从任务提交返回到异步任务执行器,可使用该执行器监视任务状态。
  • AtomicInteger: Java中的一种Integer对象,它使用硬件指令执行并发的无锁更新。
  • Condition:条件将对象监视方法(wait,notify和notifyAll()分解为不同的对象,从而通过将它们与任意Lock实现结合使用,从而使每个对象具有多个等待集。对于同步的方法和语句,Condition代替了Object监视器方法的使用,Condition是Java接口。
  • signal():唤醒一个等待的线程。
  • signalAll():唤醒所有等待的线程。
  • await():使当前线程等待,直到被信号通知或中断为止。锁定:与使用同步方法和语句相比,锁定实现提供了更广泛的锁定操作。锁是一个接口。
  • ReentrantLock:可重入互斥锁,其基本行为与隐式监视器锁相同。它是Lock的具体实现。