Java 多线程学习(三)

简介: Java 多线程学习

2.5 静态代理模式

多线程 Thread 为代理,Runnable 为被代理对象!底层就是动态代理

package com.example.democrud.democurd.test01;
/**
 * //静态代理模式
 * //真实对象和代理对象都要实现同一接口
 * //代理对象 必须要代理真实对象
 * //好处:
 *     //代理对象可以做很多真实对象做不了的事情
 *     //真实对象专注于做自己的事情
 */
public class testThred06 {
    public static void main(String[] args) {
        You you = new You();
        WeddingCompany company = new WeddingCompany(you);
        company.HappyMarry();
        new Thread( ()-> {System.out.println("我爱你");} ).start();
        new Thread( ()-> System.out.println("我爱你") ).start();
//        new Thread(Runnable::run).start();
        new WeddingCompany(you).HappyMarry(); //  2个用法一样,都是静态代理
    }
}
interface Marry{
    void HappyMarry();
}   
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("老王要结婚不知道他开心不");
    }
}
//代理角色,婚庆公司,帮助你结婚
class WeddingCompany implements Marry{
    //代理对象-->真实目标角色
    private Marry target;
    public WeddingCompany(Marry target){
        this.target=target;
    }
    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }
    private void after() {
        System.out.println("结婚后");
    }
    private void before() {
        System.out.println("结婚前");
    }
}

3、线程的6种状态

线程有6种状态,下面有错误: 
public enum State { 
//线程刚创建 
    NEW, 
//在JVM中正在运行的线程 
    RUNNABLE, 
//线程处于阻塞状态,等待监视锁,可以重新进行同步代码块中执行 
    BLOCKED, 
//等待状态 WAITING,
//调用sleep() join() wait()方法可能导致线程处于等待状态 
   TIMED_WAITING, 
//线程执行完毕,已经退出
   TERMINATED; 
}
package com.example.democrud.democurd.test01;
//观察 线程的状态
public class testState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("---等待结束");
            }
        });
        //观察线程的状态  NEW
        Thread.State state = thread.getState();
        System.out.println(state);
        //观察线程的状态   RUNNABLE
        thread.start();
        state = thread.getState();
        System.out.println(state);
    //终止线程的线程状态。线程已完成执行。 只要线程不停止运行他就会进入到此处进行运行
      while (state!=Thread.State.TERMINATED){
          Thread.sleep(100);
          state = thread.getState();//TIMED_WAITING
          System.out.println(state);
      }
    }
}

BLOCKED是指线程正在等待获取锁;WAITING是指线程正在等待其他线程发来的通知(notify),收到通知后,可能会顺序向后执行(RUNNABLE),也可能会再次获取锁,进而被阻塞住(BLOCKED)。

3.1 线程的一些常用方法

(Thread t = new Thread)线程 t 的一些方法如下图所示:

线程中常用的方法

1、public void start()  使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

2、public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run

方法;否则,该方法不执行任何操作并返回。

3、public final void setName(String name) 改变线程名称,使之与参数 name 相同

4、public final void setPriority(int piority) 更改线程的优先级。

5、public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。

6、public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。

7、public void interrupt() 中断线程。

8、public final boolean isAlive() 测试线程是否处于活动状态。

9、public static void static yield() 暂停当前正在执行的线程对象,并执行其他线程。

10、public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

11、public static Thread currentThread() 返回对当前正在执行的线程对象的引用。

配一张图:

3.1.1 线程休眠——sleep()

  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep 存在异常 InterruptedException;
  • sleep 时间达到后线程进入就绪状态;
  • sleep 可以模拟网络延时,倒计时等;
  • sleep 每一个对象都有一个锁,sleep 不会释放锁;

sleep() 方法的用处

package com.example.democrud.democurd.test01;
import java.text.SimpleDateFormat;
import java.util.Date;
public class testSleep {
    public static void main(String[] args) throws InterruptedException {
     //   tenDown();
        testDate();
    }
    public static void testDate() throws InterruptedException {
        Date date = new Date(System.currentTimeMillis());//获取系统当前的时间
        while (true){
            //休眠1秒
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
            //上面就获取了一次 每过1s咱们就需要更新一次
            date=new Date(System.currentTimeMillis());//更新当前的时间
        }
    }
    //数字倒计时demo
    public static  void tenDown() {
        int num = 10;
        try {
            while (true) {
                Thread.sleep(1000);
                System.out.println(num--);
                if (num < 0) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

主线程调用子线程的interrupt()方法,导致子线程抛出InterruptedException, 在子线程中catch这个Exception,不做任何事即可从Sleep状态唤醒线程,继续执行。

//new 一个线程
 Thread thread = new Thread(new TestThread(1));
//开启线程
thread .start();
        try {
        //休眠
            Thread.sleep(3000);
            //结束休眠开始继续运行
            thread .interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

\

3.1.2 线程礼让——yield()

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  • 将线程从运行状态转为就绪状态;
  • 让 CPU 从新调度,有可能还是调度该礼让线程。
package com.example.democrud.democurd.test01;
public class testyield {
    public static void main(String[] args) {
        yield yield = new yield();
        new Thread(yield,"a").start();
        new Thread(yield,"B").start();
    }
}
class yield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始执行");
        //礼让线程 但是不一定礼让就会成功是一个概率的事件
        //礼让线程,并不能一定成功礼让,只能让运行状态线程变为就绪状态,重新竞争,看CPU心情
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"结束执行");
    }
}

3.1.3 合并线程——Join()

Join 合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。

可以想象成插队。

package com.example.democrud.democurd.test01;
//测试Join方法
//想象为插队
//Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
public class TestJoin {
    public static void main(String[] args) throws InterruptedException {
        Join join = new Join();
        Thread thread = new Thread(join);
        thread.start();
        for (int i = 0; i < 50; i++) {
            if (i==30){
                //join插队优先进行运行
                thread.join();
            }
            System.out.println("main"+i);
        }
    }
}
class Join implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我是vip的线程");
        }
    }
}

3.2 停止线程的方式

第一种:标志位

  • 不推荐使用 JDK 提供的 stop ()、destroy()方法。【已弃用】
  • 推荐线程自己停止下来
  • 建议使用一个标志位进行终止变量 , 当 flag == false,则终止线程运行。

线程的停止

package com.example.democrud.democurd.test01;
//测试stop
//1.建议线程正常停止--->利用次数,不建议死循环。
//2.建议使用标志位--->设置一个标志位.
//3.不要使用stop或destroy等过时或JDK不建议使用的方法
public class testStop implements Runnable {
    private Boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("执行线程任务进行中"+i++);
        }
    }
    public void stop() {
        this.flag = false;
    }
    public static void main(String[] args) {
        testStop stop = new testStop();
        new Thread(stop).start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main"+i);
            if (i == 90) {
                stop.stop();
                System.out.println("执行到90停止");
            }
        }
    }
}

第二种: interrupt方法

1、直接调用interrupt()方法

package com.example.democrud.democurd.test01;
public class testStop01 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            //直接调用interrupt
            while (!Thread.interrupted()){
                System.out.println("你好啊");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //加入break才是终止执行
                    break;
                }
            }
            System.out.println("停止");
        });
        t1.start();
        Thread.sleep(2000);
        System.out.println("终止");
        //让t1终止 使用此方法
        t1.interrupt();
    }
}



2、拿到当前线程在调用interrupt()方法(Thread.currentThread().isInterrupted())

public class ThreadDemo14 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            //拿到当前线程 判断是否终止
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("别烦我");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //加入break才是终止执行
                break;
            }
        }
            System.out.println("转账终止");
        });
        t1.start();
        Thread.sleep(2000);
        System.out.println("有内鬼终止交易");
        //让t1终止 使用此方法
        t1.interrupt();
    }
}

注:当调用interrupt方法时,一定要加上break终止代码否则只会出现暂时终止。\

调用interrupt()方法的两种方法的区别

Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志,也就是复位

public class ThreadDemo16 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            while (!Thread.interrupted()){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //获取当前线程
                    Thread curr=Thread.currentThread();
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("---------------------");
                    Thread.interrupted();
                   //Thread.currentThread().interrupt();
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }
}


Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志,不会复位

public class ThreadDemo16 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            while (!Thread.interrupted()){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //获取当前线程
                    Thread curr=Thread.currentThread();
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("---------------------");
                   // Thread.interrupted();
                   Thread.currentThread().interrupt();
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                    System.out.println("打印当前线程状态"+curr.isInterrupted());
                }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }
}

打印结果

补:线程中的重要属性
public class ThreadDemo11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
          for (int i=0;i<10;i++){
              try {
                  Thread.sleep(100);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
        });
        //重要属性
        System.out.println("线程的ID:"+t1.getId());
        System.out.println("线程的名称:"+t1.getName());
        System.out.println("线程的优先级:"+t1.getPriority());
        System.out.println("线程的状态:"+t1.getState());
        System.out.println("线程的类型:"+t1.isDaemon());
        System.out.println("线程是否存活:"+t1.isAlive());
        t1.start();

Thread的中断机制(interrupt) (扩展)

相关文章
|
8天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
10天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
10天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
10天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
33 3
|
10天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
91 2
|
18天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
46 6
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
27天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
27天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
50 3
|
28天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####