Java 并发一,基础概念和入门

#线程基本概念和使用方法#

  • 线程的定义和作用

    • 线程是操作系统能够进行运算调度的最小单位(程序执行的最小单元),它被包含在进程之中,是进程中实际运行的实体
    • 线程的创建
      • 继承Thread类并重写run方法
      • 实现Runable接口并实现run方法,然后传给Thread对象
      • 实现Callable<T>接口并实现call方法
package com.msq.pattern.thread;

import java.util.concurrent.*;

public class ThreadCreateDemo {

  public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 1.继承thread类
    // 1.1新建一个线程
    MyThread myThread = new MyThread();
    // 1.2调用start方法开启这个线程
    myThread.start();


    // 2. 实现runnable接口
    // 2.1将Runnable实现类的实例传递给Thread类的构造器,创建线程对象。
    Thread thread = new Thread(new MyThread2());
    // 2.2调用线程对象的start()方法启动线程。
    thread.start();

    // 3,实现callable<T>接口,T 返回值类型
    MyThread3 myThread3 = new MyThread3();
    // 3.1 通过ExecutorService提交Callable任务,并返回一个Future对象。
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Future<String> submit = executorService.submit(myThread3);
    // 3.2使用Future对象来获取任务的结果。
    // 等待结果并获取
    System.out.println("result:"+submit.get());
    executorService.shutdown();

    //---------------
    Callable<String> task = () -> {
      return "result";
    };
    Thread task1 = new Thread(()-> {
      System.out.println("result");
    });
    ExecutorService executor = Executors.newFixedThreadPool(10); // 创建固定大小的线程池
    executor.execute(new MyThread());
    ExecutorService executor1 = Executors.newCachedThreadPool(); // 创建可缓存的线程池
    executor.submit(() -> {
      // 线程执行的代码
    });
  }

  // 实现Callable接口。
  static class MyThread3 implements Callable<String>{
    @Override
    public String call() throws Exception {
      return "result";
    }
  }

  // 实现Runnable接口。
  static class MyThread2 implements Runnable{
    @Override
    public void run() {
      System.out.println("线程执行的代码:实现接口");
    }
  }

  // 继承thread类,重写run方法
  static class MyThread extends Thread{
    @Override
    public void run() {
      System.out.println("线程运行的代码,继承类");
    }
  }



}
  • 线程的基本属性和方法
    • 线程属性:

      • Name - 线程的名称,可以通过getName()获取,setName(String name)设置。
      • Priority - 线程的优先级,可以通过getPriority()获取,setPriority(int priority)设置。优先级范围是1到10。
      • Thread Group - 线程所属的线程组,可以通过getThreadGroup()获取。
      • Daemon Status - 守护线程状态,守护线程可以在用户线程执行完毕之后结束,通过isDaemon()检查,setDaemon(boolean on)设置。
      • State - 线程的状态,如新建、就绪、运行、阻塞、等待、超时等待、终止等,可以通过getState()获取。
    • 线程方法:

      • start() - 启动线程,使得线程进入就绪状态。
      • run() - 包含线程执行的代码,可以被重写。
      • join() - 等待该线程终止。
      • sleep(long millis) - 使当前线程暂停执行指定的时间。
      • interrupt() - 中断线程,设置中断状态。
        • 调用线程的 interrupt() 方法会将该线程的中断状态设置为 true
        • 这个方法不会立即停止线程正在执行的操作,而是提供一个信号,表明线程应该在合适的时候停止。
        • InterruptedException ,当线程处于等待、休眠或其他一些特定状态时,如果此时线程的中断状态被设置为 true,那么这些特定的方法会抛出 InterruptedException。
        • 可以使用volatile或者原子类自己判断是否要中断(结束)
        • 守护线程(Daemon thread)不会阻止JVM退出。即使守护线程正在运行,JVM也会在所有非守护线程结束时退出。
      • isInterrupted() - 检查当前线程是否被中断。
      • currentThread() - 返回执行当前代码的线程对象。
      • yield() - 暂停当前线程对象的执行,让其他同优先级的线程有机会执行。
      • setName(String name) - 设置线程的名字。
      • getName() - 获取线程的名字。
      • setPriority(int priority) - 设置线程的优先级。
      • getPriority() - 获取线程的优先级。
      • setDaemon(boolean on) - 将线程设置为守护线程或用户线程。
      • isDaemon() - 检查线程是否是守护线程。
      • getThreadGroup() - 获取线程所属的线程组。
      • getState() - 返回线程的状态。
      • toString() - 返回线程的字符串表示,通常包含线程名称、优先级和线程ID。
Thread thread = new Thread(() -> {
    // 线程执行的代码
});

// 获取和设置线程名称
String name = thread.getName();
thread.setName("MyThread");

// 获取和设置线程优先级
int priority = thread.getPriority();
thread.setPriority(Thread.MAX_PRIORITY);

// 启动线程
thread.start();

// 等待线程终止
try {
    thread.join();
} catch (InterruptedException e) {
    // 线程中断异常处理
}

// 检查线程是否为守护线程
boolean isDaemon = thread.isDaemon();
thread.setDaemon(true);
 线程中断的列子:
public class InterruptibleTask implements Runnable {
    private volatile boolean running = true;

    @Override
    public void run() {
        System.out.println("任务开始执行,线程名称:" + Thread.currentThread().getName());

        try {
            while (running) {
                // 模拟业务逻辑处理
                System.out.println("任务正在执行...");

                // 假设业务逻辑需要一些时间来完成
                Thread.sleep(1000);

                // 检查中断状态,如果线程被中断,跳出循环
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("检测到中断信号,准备退出循环。");
                    break;
                }
            }
        } catch (InterruptedException e) {
            // 捕获到InterruptedException,说明线程在等待时被中断
            System.out.println("在等待时被中断,准备退出循环。");
            // 清除中断状态,以便后续操作可以使用interrupt()再次中断
            Thread.currentThread().interrupt();
        } finally {
            // 清理资源
            cleanUp();
        }

        System.out.println("任务执行完毕,线程名称:" + Thread.currentThread().getName());
    }

    // 模拟清理资源的方法
    private void cleanUp() {
        running = false;
        System.out.println("资源清理完成。");
    }

    // 主方法,用于启动线程并演示中断
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new InterruptibleTask());
        thread.start();

        // 让主线程睡眠一会儿,以便任务线程有时间执行
        Thread.sleep(3000);

        // 中断任务线程
        thread.interrupt();

        // 等待任务线程完成
        thread.join();
    }
}

#进程和线程的区别#

进程:进程是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的实例。每个进程都有自己的独立内存空间,一个进程至少有一个线程

线程:线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如执行栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源

  • 资源拥有
    • 进程拥有独立的内存空间和系统资源,进程间的资源相互独立。
    • 线程共享进程的内存空间和资源,一个线程的执行状态(如寄存器、堆栈等)对于同进程的其他线程是可见的。
  • 独立性
    • 进程是独立运行的,一个进程崩溃不会直接影响到其他进程(除非它们有共享资源)。
    • 线程是进程的一部分,一个线程的崩溃可能会导致整个进程的崩溃。
  • 通信方式
    • 进程间通信(IPC)需要特定的机制,如管道、消息队列、共享内存或套接字等。
    • 线程间可以直接读写进程的共享内存,通信更为方便。
  • 执行
    • 每个进程有自己的程序计数器(PC),操作系统通过程序计数器来跟踪进程执行到何处。
    • 线程共享进程的程序计数器,每个线程有自己的程序计数器。

#Java多线程及基础#

多线程的概念

  • 线程的创建

  • 线程的启动

    • 调用线程对象的start()方法启动线程。这会导致线程的run()方法被执行。
  • 线程的生命周期

    • 新建(New):线程对象被创建。
    • 就绪(Runnable):线程可能正在运行,或者正在等待CPU时间片。
    • 运行(Running):线程正在执行其run()方法。
    • 阻塞(Blocked):线程等待某些条件(如I/O操作或获取同步锁)。
    • 死亡(Terminated):线程执行完毕或被强制终止。
  • 线程的调度

    • Java线程的调度由JVM和底层操作系统共同管理。Java提供了一些方法来控制线程的调度,如yield()sleep()
  • 线程的优先级

    • 线程具有优先级属性,可以通过setPriority(int)设置。高优先级的线程更可能获得CPU时间。
  • 线程的同步

    • 多线程环境下,多个线程可能会访问共享资源,需要同步机制来避免数据不一致。Java提供了synchronized关键字和其他同步工具(如ReentrantLock)。
  • 线程间通信

    • 线程可以通过共享变量、等待/通知机制(wait()notify()notifyAll())等方式进行通信。
  • 线程的中断

    • 线程可以通过interrupt()方法请求中断,被请求中断的线程应该检查中断状态,并在适当的时候响应中断。
  • 并发集合

    • Java提供了一些线程安全的集合类,如ConcurrentHashMapCopyOnWriteArrayList等,适用于多线程环境。
  • 线程池

    • 线程池用于管理线程的创建和销毁,提高资源利用率和执行效率。Java的java.util.concurrent包提供了多种线程池实现。
  • 并发工具类

    • CountDownLatchCyclicBarrierSemaphoreExchanger等,这些工具类可以帮助开发者更容易地处理复杂的并发问题。
  • 死锁

    • 死锁是多个线程相互等待对方持有的资源,导致程序停滞。Java提供了一些机制来预防和诊断死锁。
  • Java内存模型(JMM)

    • 定义了线程如何通过内存进行通信,包括主内存和工作内存的概念,以及happens-before原则等。

线程的状态转换

  • 新建(New):

    • 这是线程对象被创建且尚未启动的状态。线程此时还没有分配给JVM。
  • 可运行\就绪(Runnable):

    • 线程被创建并调用了start()方法后,它进入可运行状态。此时线程具备了运行的条件,但可能正在等待JVM分配CPU时间片。
  • 运行(Running):

    • 可运行状态的线程一旦获得CPU时间片,就会进入运行状态开始执行run()方法。
  • 阻塞(Blocked):

    • 当线程试图获取一个已被其他线程持有的锁时,它将进入阻塞状态。线程会等待直到锁被释放。
  • 等待(Waiting):

    • 线程因为调用了Object.wait()而在没有指定超时值的情况下进入等待状态。它需要其他线程调用相同对象的Object.notify()Object.notifyAll()来唤醒。
  • 超时等待(Timed Waiting):

    • 当线程调用了带有超时参数的Object.wait(long timeout)Thread.sleep(long millis)Thread.join(long millis)等方法时,它将进入超时等待状态。线程会在指定的超时时间后自动唤醒。
  • 终止(Terminated)-列子:
    • 线程完成了它的run()方法,或者被其他线程通过Thread.stop()方法(已过时,不推荐使用)强制终止后,进入终止状态。
    • public class ControlledThread implements Runnable {
          private volatile boolean running = true;
      
          @Override
          public void run() {
              while (running) {
                  // 执行任务
              }
          }
      
          public void stopRunning() {
              running = false;
          }
      }

#线程同步机制(synchronize、locks等)#

线程同步是多线程编程中的一个重要概念,用于控制对共享资源的并发访问,以防止数据不一致和竞争条件。以下是`synchronized`关键字的使用和锁的概念及作用的详细说明:

synchronized 关键字的使用

synchronized关键字在Java中用于实现同步锁,它可以确保同一时刻只有一个线程能够执行特定代码段。

  •  同步实例方法

   当在实例方法上使用`synchronized`关键字或在方法内部使用`synchronized`块时,锁住的是当前实例对象(this)

public synchronized void myMethod() {
    // 只有获得当前实例锁的线程可以执行此代码
}

  •  同步静态方法

   在静态方法上使用`synchronized`关键字时,锁住的是这个类的Class对象。

   public static synchronized void myStaticMethod() {
       // 只有获得该类Class对象锁的线程可以执行此代码
   }

  • 同步代码块

   可以对任意对象加锁,通过在代码块前使用synchronized关键字和。

public void myMethod() {

        Object lock = new Object();
        synchronized (lock) {

                 // 只有获得指定对象锁的线程可以执行此代码块

        }

}

  • 锁的释放

   当执行完`synchronized`块内的代码后,锁会自动释放,允许其他线程进入同步块。

锁的概念和作用

  • 锁的概念

   锁是一种同步机制,用于控制对共享资源的访问。在多线程环境中,锁可以确保每次只有一个线程能够访问特定的代码段或资源。

  • 内置锁 Monitor

   Java的每个对象都有一个内置锁(也称为监视器锁),synchronized关键字就是利用这个内置锁来实现线程同步。

  • 锁的作用

   - 确保线程安全:防止多个线程同时修改共享数据,导致数据不一致。
   - 保证执行顺序:通过锁可以控制线程的执行顺序,实现复杂的同步逻辑。

  • 锁的公平性

   - 锁可以是公平或非公平的。公平锁按照线程请求的顺序授予锁,非公平锁则允许线程抢占。

  • 锁的其他实现

   - 除了`synchronized`关键字,Java还提供了其他锁实现,如ReentrantLock、ReadWriteLock等,它们提供了更灵活的锁定操作。
   - synchronized关键字的使用比较简单直观。
   - 它在竞争激烈的情况下性能可能不如一些其他的锁实现,但在低竞争环境下表现良好。

  • 锁的问题

   - 可能导致死锁。
   - 不支持响应中断,即不能在等待锁的过程中响应线程中断。


 

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值