17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(中)

简介: 17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)

17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(上):https://developer.aliyun.com/article/1580253

17.3线程状态


17.3.1 线程状态

线程状态:新建、就绪、运行、终止。

17.3.2 常见方法

方法名 说明
public static void sleep(long millis) 当前线程主动休眠 millis 毫秒。
public static void yield() 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
public final void join() 允许其他线程加入到当前线程中。
public void setPriority(int) 线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多。
public void setDaemon(boolean) 设置为守护线程线程有两类:用户线程(前台线程)、守护线程(后台线程)

17.3.3 线程状态(等待)

线程状态:新建、就绪、运行、等待、终止。

17.4 线程安全


为什么会出现线程安全问题?

  • 需求:A线程将“Hello”存入数组;B线程将“World”存入数组。
  • 线程不安全:
  • 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
  • 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
  • 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。

案例演示:

public class ThreadSafe {
  private static int index=0;
  public static void main(String[] args)  throws Exception{
    //创建数组
    String[] s=new String[5];
    //创建两个操作
    Runnable runnableA=new Runnable() {
      
      @Override
      public void run() {
        //同步代码块
        synchronized (s) {
          s[index]="hello";
          index++;
        }
        
      }
    };
    Runnable runnableB=new Runnable() {
      
      @Override
      public void run() {
        synchronized (s) {
          s[index]="world";
          index++;
        }
        
      }
    };
    
    //创建两个线程对象
    Thread a=new Thread(runnableA,"A");
    Thread b=new Thread(runnableB,"B");
    a.start();
    b.start();
    
    a.join();//加入线程
    b.join();//加入线程
    
    System.out.println(Arrays.toString(s));
    
  }
}


17.4.1 同步代码块

语法:

synchronized(临界资源对象){ //对临界资源对象加锁

//代码(原子操作)

}

注意:

演示案例:

Ticket类:

public class Ticket implements Runnable{
  
  private int ticket=100;
  //创建锁
  //private Object obj=new Object();
  
  @Override
  public void run() {
    
    while(true) {
      synchronized (this) {//this ---当前对象
        if(ticket<=0) {
          break;
        }
        System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"票");
        ticket--;
      }
      
    }
  }
  
}

17.4.2 线程状态(阻塞)

线程状态:新建、就绪、运行、阻塞、终止。

17.4.3 同步方法

语法:

synchronized 返回值类型 方法名称(形参列表){ //对当前对象(this)加锁

// 代码(原子操作)

}

注意:

17.4.4 同步规则

  • 只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记。
  • 如调用不包含同步代码块的方法,或普通方法时,则不需要锁标记,可直接调用。

JDK中线程安全的类:

  • StringBuffer
  • Vector
  • Hashtable
    以上类中的公开方法,均为synchonized修饰的同步方法。

17.5 死锁

17.5.1 什么是死锁?

  • 当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁。
  • 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。

17.5.2 死锁案例

MyLock类:

public class MyLock {
  //两个锁(两个筷子)
  public static Object a=new Object();
  public static Object b=new Object();
}

BoyThread类:

public class Boy extends Thread{
  @Override
  public void run() {
    synchronized (MyLock.a) {
      System.out.println("男孩拿到了a");
      synchronized (MyLock.b) {
        System.out.println("男孩拿到了b");
        System.out.println("男孩可以吃东西了...");
      }
    }
  }
}

GirlThread类:

public class Girl extends Thread {
  @Override
  public void run() {
    synchronized (MyLock.b) {
      System.out.println("女孩拿到了b");
      synchronized (MyLock.a) {
        System.out.println("女孩拿到了a");
        System.out.println("女孩可以吃东西了...");
      }
    }
  }
}

TestDeadLock类:

public class TestDeadLock {
  public static void main(String[] args) {
    Boy boy=new Boy();
    Girl girl=new Girl();
    girl.start();
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
    boy.start();
  }
}

17.6 线程通信


17.6.1 线程通信方法

方法 说明
public final void wait() 释放锁,进入等待队列
public final void wait(long timeout) 在超过指定的时间前,释放锁,进入等待队列
public final void notify() 随机唤醒、通知一个线程
public final void notifyAll() 唤醒、通知所有线程

注意:所有的等待、通知方法必须在对加锁的同步代码块中。

17.6.2 生产者消费者

若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区中,消费者从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个满的缓冲区中放入产品。

Bread类:

pupublic class Bread {
  private int id;
  private String productName;
  public Bread() {
    // TODO Auto-generated constructor stub
  }
  public Bread(int id, String productName) {
    super();
    this.id = id;
    this.productName = productName;
  }
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getProductName() {
    return productName;
  }
  public void setProductName(String productName) {
    this.productName = productName;
  }
  @Override
  public String toString() {
    return "Bread [id=" + id + ", productName=" + productName + "]";
  }
}

BreadCon类:

public class BreadCon {
  //存放面包的数组
  private Bread[] cons=new Bread[6];
  //存放面包的位置
  private int index=0;
  
  //存放面包
  public synchronized void input(Bread b) { //锁this
    //判断容器有没有满
    while(index>=6) {
      try {
        this.wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    
    cons[index]=b;
    System.out.println(Thread.currentThread().getName()+"生产了"+b.getId()+"");
    index++;
    //唤醒
    this.notifyAll();
    
    
    
  }
  //取出面包
  public synchronized void output() {//锁this
    while(index<=0) {
      try {
        this.wait();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    index--;
    Bread b=cons[index];
    System.out.println(Thread.currentThread().getName()+"消费了"+b.getId()+" 生产者:"+b.getProductName());
    cons[index]=null;
    //唤醒生产者
    this.notifyAll();
  }
}

Consume类:

public class Consume implements Runnable{

  private BreadCon con;
  
  public Consume(BreadCon con) {
    super();
    this.con = con;
  }

  @Override
  public void run() {
    for(int i=0;i<30;i++) {
      con.output();
    }
  }

}

Produce类:

public class Prodcut implements Runnable {

  private BreadCon con;
  
  public Prodcut(BreadCon con) {
    super();
    this.con = con;
  }

  @Override
  public void run() {
    for(int i=0;i<30;i++) {
      con.input(new Bread(i, Thread.currentThread().getName()));
    }
  }
  
}

Test类:

public class Test {
  public static void main(String[] args) {
    //容器
    BreadCon con=new BreadCon();
    //生产和消费
    Prodcut prodcut=new Prodcut(con);
    Consume consume=new Consume(con);
    //创建线程对象
    Thread chenchen=new Thread(prodcut, "晨晨");
    Thread bingbing=new Thread(consume, "消费");
    Thread mingming=new Thread(prodcut, "明明");
    Thread lili=new Thread(consume, "莉莉");
    //启动线程
    chenchen.start();
    bingbing.start();
    mingming.start();
    lili.start();
  }
}

17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下):https://developer.aliyun.com/article/1580256

目录
相关文章
|
1月前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
9天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
30 5
|
22天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
22天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
15天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
15天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
40 3
|
21天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
78 6
|
21天前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
32 4
|
21天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
54 1
|
29天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
52 6
下一篇
DataWorks