java-并发编程

本文涉及的产品
私网连接 PrivateLink,5万GB流量 1.5万小时实例时长
简介: 1、并发编程  并发通常能提高单处理器的程序性能。可是,看到这句话有些违背直觉。多线程的运行增加了线程间切换的开销,仅仅从这个角度看,单线程运行总比多线程的性能好。但是,程序的阻塞会使得结果不一样,当某个线程阻塞时候,其它线程仍然可以执行,因此程序仍保持运行。

1、并发编程

  并发通常能提高单处理器的程序性能。可是,看到这句话有些违背直觉。多线程的运行增加了线程间切换的开销,仅仅从这个角度看,单线程运行总比多线程的性能好。但是,程序的阻塞会使得结果不一样,当某个线程阻塞时候,其它线程仍然可以执行,因此程序仍保持运行。充分利用cpu的时间提高的性能远大于线程间的切换带来的性能下降。

何为阻塞:程序中某个线程由于在不满足某些条件的情况下而导致不能够继续执行的现象

2、基本线程机制:

  一个程序可以分为多个独立运行任务,每个独立任务由线程驱动执行。线程并发执行,表面看起来是同时执行,好像各自都有一个自己的CPU一样。实际上,底层机制是CPU将时间片分给各个线程,一个时间只能有一个线程获得CPU的时间片,也就是线程独占CPU资源。

3、定义任务类、定义线程类

定义任务

package com.duoxiancheng;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

public static void main(String[] args) {

for (int i=0; i<2; i++) {
new Thread(new LiftOff()).start();
}
}
}

class LiftOff implements Runnable{
private int countDown=3;
private static int taskCount=0;
private final int id=taskCount++;

@Override
public void run() {
while (countDown-->0) {
System.out.println("#id=" + id + " countDown="+(countDown > 0 ? countDown : "LiftOff!"));
Thread.yield();
}
}
}

输出结果

#id=0 countDown=2
#id=1 countDown=2
#id=0 countDown=1
#id=1 countDown=1
#id=0 countDown=LiftOff!
#id=1 countDown=LiftOff!

定义线程类

package com.duoxiancheng;

public class Main {

> > public static void main(String[] args) {

for (int i=0; i<2; i++) {
new LiftOff().start();
}
}
}

class LiftOff extends Thread{
private int countDown=3;
private static int taskCount=0;
private final int id=taskCount++;

@Override
public void run() {
while (countDown-->0) {
System.out.println("#id=" + id + " countDown="+(countDown > 0 ? countDown : "LiftOff!"));
Thread.yield();
}
}
}

4、线程池

待续...

5、从任务中产生返回值---Callable<T>接口

package com.duoxiancheng;

import java.util.concurrent.*;

public class Main1 {
public static void main(String[] args) throws Exception{

    ExecutorService executorService= Executors.newCachedThreadPool();
    for (int i=0;i&lt;50;i++){
        Future future = executorService.submit(new TaskWithResult(i));
        Object result = future.get();
        System.out.println(result);
    }
}

}
class TaskWithResult implements Callable{
private int id=0;
public TaskWithResult(int id){br/>this.id=id;
}
@Override
public Object call() throws Exception {
return id;
}
}

其中 future.get()是阻塞的方法;如果想想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式

6、常用方法

休眠---sleep()

让步---yield()

加入一个线程---join()

优先级--setPriority()/getPriority()

后台线程--setDaemon()/isDaemon()

...

7、捕获线程中的异常

线程中抛出异常,会传播到控制台,除非采用特殊手段。

public interface Runnable {
public abstract void run();
}
在run()方法内部try-catch-finally捕获异常
使用异常处理器捕获异常--异常处理器实现Thread.UncaughtExceptionHandler接口
以下分析自定义异常处理器:

为线程设置异常处理器。具体做法可以是以下几种:
(1)Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;
(2)Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;
如果当前线程有异常处理器(默认没有),则优先使用该UncaughtExceptionHandler类;否则,如果当前线程所属的线程组有异常处理器,则使用线程组的
UncaughtExceptionHandler;否则,使用全局默认的DefaultUncaughtExceptionHandler;如果都没有的话,子线程就会退出

package com.duoxiancheng;

import java.util.concurrent.ThreadFactory;

public class Main2 {

public static void main(String[] args) {

    Thread thread=new Thread(new ExceptionThread());
    thread.setUncaughtExceptionHandler(new MyExceptionHandler());
    thread.start();
}

}

/**

  • 任务类
    */
    class ExceptionThread implements Runnable{

    @Override
    public void run() {
    Thread t = Thread.currentThread();
    System.out.println("ExceptionThread 当前线程信息:"+t.toString());
    System.out.println("当前线程ExceptionThread的异常处理器"
    +t.getUncaughtExceptionHandler());
    throw new RuntimeException();
    }
    }

/**

8、共享资源

共享资源竞争:
  导致线程安全问题

解决思想:
  多人(线程)都希望单独使用浴室(共享资源)。为了使用浴室,一个人先敲门,看能不能使用。如果没人回话,他就进入浴室并锁上门(获得锁)。这时候,其它人想使用浴室的话,就会被阻挡在外面(不能获取锁),直到浴室可以使用。浴室外面的人没有排队,浴室门打开(前一个人释放锁),离门最近的人优先进入使用(获得锁,设置优先级和yield方法可以建议某个优先使用)。

解决方式:
  Synchronized 、Lock锁同步以及Voliate修饰符和原子类

  线程本地存储---ThreadLocal

9、线程之间协作

生产者与消费者

package com.duoxiancheng;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**

  • 生产者-消费者
    */
    public class Main3 {

    public static void main(String[ ] args) throws InterruptedException {
    Restaurant restaurant=new Restaurant();
    new Thread(new ProductorThread(restaurant)).start();
    Thread.sleep(20);
    new Thread(new ConsumerThread(restaurant)).start();
    }
    }
    class Restaurant {

    Lock lock=new ReentrantLock();//锁
    Condition condition1=lock.newCondition();//条件1
    Condition condition2=lock.newCondition();//条件2

    private int count;//已做好的餐

    private int count2;

    /**

    • 消费者方法
      */
      public void comsumer(){
      lock.lock();
      try {
      if (count==0) {
      System.out.println(Thread.currentThread().getId()+"客户 想要一份快餐!");
      condition2.signalAll();
      System.out.println(Thread.currentThread().getId()+"客户 等待一份快餐!");
      condition1.await();
      }
      count--;
      System.out.println(Thread.currentThread().getId()+ "客户 消费了一份快餐!");
      } catch (InterruptedException e) {
      e.printStackTrace();
      }finally {
      lock.unlock();
      }
      }
      /**
    • 生产者方法
      */
      public void productor(){
      lock.lock();
      try {
      condition2.await();
      count++;//生产一份快餐
      System.out.println(Thread.currentThread().getId()+ "厨师 制作了一份快餐!");
      condition1.signalAll();
      System.out.println(Thread.currentThread().getId()+"厨师 通知客户使用");
      }catch (InterruptedException e){
      e.printStackTrace();
      }finally {
      lock.unlock();
      }
      }
      }

/**

  • 消费者
    */
    class ConsumerThread implements Runnable{

    private Restaurant restaurant;

    public ConsumerThread(Restaurant restaurant){
    this.restaurant=restaurant;
    }

    @Override
    public void run() {
    restaurant.comsumer();
    }
    }

/**

  • 生产者
    */
    class ProductorThread implements Runnable{

    private Restaurant restaurant;

    public ProductorThread(Restaurant restaurant){
    this.restaurant=restaurant;
    }

    @Override
    public void run() {
    restaurant.productor();
    }
    }

输出结果:

11客户 想要一份快餐!
11客户 等待一份快餐!
10厨师 制作了一份快餐!
10厨师 通知客户使用
11客户 消费了一份快餐!

生产者与消费者 和 队列
  使用wait()、notifyAll() 是一种解决任务互操作问题非常低级的方式。使用同步队列来解决任务协作问题,同步队列在任何时刻只允许一个任务插入或移除。

java.util.concurrent.BlockingQueue接口提供了这个同步队列,其有大量的实现。通常可以使用LinkedBlockingDeque(×××队列) 和 ArrayBlockingDeque(固定尺寸队列)。

消费者任务试图从队列中获取对象,而该队列此时为空,那这些队列还可以挂起消费者任务(阻塞);当有更多元素可用时恢复消费者任务。阻塞队列可以解决非常大量的问题。

package com.duoxiancheng;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;

/**

  • 生产者-消费者与队列
    */
    public class Main4 {

    public static void main(String[] args) {

    ExecutorService executorService= Executors.newCachedThreadPool();
    
    LinkedBlockingDeque&lt;Toast&gt; toastQueue=new LinkedBlockingDeque&lt;&gt;();
    LinkedBlockingDeque&lt;Toast&gt; butteredQueue=new LinkedBlockingDeque&lt;&gt;();
    LinkedBlockingDeque&lt;Toast&gt; jammedQueue=new LinkedBlockingDeque&lt;&gt;();
    
    executorService.execute(new Toaster(toastQueue));
    executorService.execute(new Butterer(toastQueue, butteredQueue));
    executorService.execute(new Jammed(butteredQueue, jammedQueue));
    executorService.execute(new Eater(jammedQueue));

    }
    }

class Toast{

private Status status=Status.DRY;
private final int id;
public Toast(int id) {
    this.id = id;
}
public int getId() {
    return id;
}
public Status getStatus() {
    return status;
}
public void addButtered(){
    status=Status.BUTTERED;
}
public void addJammed(){
    status=Status.JAMMED;
}
@Override
public String toString() {
    return "Toast "+id+" : "+status;
}

/**
 * 枚举类型
 */
public enum Status{
    DRY,BUTTERED,JAMMED
}

}

/**

/**

/**

/**

输出结果:

Toast 0 : DRY
添加黄油, Toast 0 : BUTTERED
添加果酱, Toast 0 : JAMMED
消费了一个吐司
Toast 1 : DRY
添加黄油, Toast 1 : BUTTERED
添加果酱, Toast 1 : JAMMED
消费了一个吐司
Toast 2 : DRY
添加黄油, Toast 2 : BUTTERED
添加果酱, Toast 2 : JAMMED
消费了一个吐司
Toast 3 : DRY
添加黄油, Toast 3 : BUTTERED
添加果酱, Toast 3 : JAMMED
消费了一个吐司
Toast 4 : DRY
添加黄油, Toast 4 : BUTTERED
添加果酱, Toast 4 : JAMMED
消费了一个吐司

10、死锁

某个线程在等待另一个线程释放锁,而后者又在等别的线程的所,这样一直下去,直到整个链条上的线程又在等第一个线程释放锁。这样线程之间的相互等待的连续循环,导致没有哪个线程能继续执行的现象。

死锁四大条件:

请求与保持

不可剥夺

互斥条件

循环等待

防止死锁:
发生死锁必须全部满足四大条件,要避免死锁,只需破坏其中一个即可。

目录
相关文章
|
27天前
|
Java 程序员 调度
【JAVA 并发秘籍】进程、线程、协程:揭秘并发编程的终极武器!
【8月更文挑战第25天】本文以问答形式深入探讨了并发编程中的核心概念——进程、线程与协程,并详细介绍了它们在Java中的应用。文章不仅解释了每个概念的基本原理及其差异,还提供了实用的示例代码,帮助读者理解如何在Java环境中实现这些并发机制。无论你是希望提高编程技能的专业开发者,还是准备技术面试的求职者,都能从本文获得有价值的见解。
33 1
|
11天前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
12天前
|
安全 Java 测试技术
掌握Java的并发编程:解锁高效代码的秘密
在Java的世界里,并发编程就像是一场精妙的舞蹈,需要精准的步伐和和谐的节奏。本文将带你走进Java并发的世界,从基础概念到高级技巧,一步步揭示如何编写高效、稳定的并发代码。让我们一起探索线程池的奥秘、同步机制的智慧,以及避免常见陷阱的策略。
|
28天前
|
安全 Java 编译器
深入Java内存模型:解锁并发编程的秘密
【8月更文挑战第24天】在Java的世界,内存模型是支撑并发编程的基石。本文将深入浅出地探讨Java内存模型(JMM)的核心概念、工作原理及其对高效并发策略的影响。我们将通过实际代码示例,揭示如何利用JMM来设计高性能的并发应用,并避免常见的并发陷阱。无论你是Java新手还是资深开发者,这篇文章都将为你打开并发编程的新视角。
31 2
|
1月前
|
缓存 Java 数据处理
Java中的并发编程:解锁多线程的力量
在Java的世界里,并发编程是提升应用性能和响应能力的关键。本文将深入探讨Java的多线程机制,从基础概念到高级特性,逐步揭示如何有效利用并发来处理复杂任务。我们将一起探索线程的创建、同步、通信以及Java并发库中的工具类,带你领略并发编程的魅力。
|
1月前
|
Java 调度 开发者
Java并发编程:解锁多线程同步的奥秘
在Java的世界里,并发编程是提升应用性能的关键所在。本文将深入浅出地探讨Java中的并发工具和同步机制,带领读者从基础到进阶,逐步掌握多线程编程的核心技巧。通过实例演示,我们将一起探索如何在多线程环境下保持数据的一致性,以及如何有效利用线程池来管理资源。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你对Java并发编程有更深入的理解和应用。
|
1月前
|
算法 安全 Java
Java中的并发编程:从基础到高级
在Java的世界中,并发编程是一块基石,它允许多个操作同时进行,极大地提高了程序的效率和性能。本文将深入探讨Java并发编程的核心概念、实用工具和高级技术,旨在为读者提供一套完整的解决方案,以应对复杂的并发挑战。我们将从线程的基础讲起,逐步过渡到线程池的使用,最后探讨Java并发包中的强大工具,如CyclicBarrier和Semaphore等。
21 4
|
1月前
|
算法 安全 Java
探索Java中的并发编程:挑战与解决方案
【8月更文挑战第9天】 在Java世界中,并发编程是一个既令人兴奋又充满挑战的领域。它不仅为开发者提供了提高应用程序性能和响应性的机会,还带来了诸如数据一致性、线程安全和死锁等复杂问题。本文旨在通过分析Java并发的核心概念、常见并发模式及其实现方式,探讨如何在Java中有效地管理多线程环境,同时识别并解决并发编程过程中可能遇到的常见问题。
|
21天前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
41 0
|
1月前
|
Java API 开发者
Java中的并发编程:解锁多线程的潜力
在数字化时代的浪潮中,并发编程已成为软件开发的核心技能之一。本文将深入探讨Java中的并发编程概念,通过实例分析与原理解释,揭示如何利用多线程提升应用性能和响应性。我们将从基础的线程创建开始,逐步过渡到高级的同步机制,并探讨如何避免常见的并发陷阱。读者将获得构建高效、稳定并发应用所需的知识,同时激发对Java并发更深层次探索的兴趣。
33 2