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) (扩展)

相关文章
|
1天前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
15 5
|
1天前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
1天前
|
存储 算法 搜索推荐
滚雪球学Java(27):从零开始学习数组:定义和初始化
【5月更文挑战第2天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
7 3
|
2天前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
10 3
|
2天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
53 2
|
2天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
40 3
|
2天前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
3 0
|
2天前
|
Java 调度
Java并发编程:深入理解线程池
【5月更文挑战第11天】本文将深入探讨Java中的线程池,包括其基本概念、工作原理以及如何使用。我们将通过实例来解释线程池的优点,如提高性能和资源利用率,以及如何避免常见的并发问题。我们还将讨论Java中线程池的实现,包括Executor框架和ThreadPoolExecutor类,并展示如何创建和管理线程池。最后,我们将讨论线程池的一些高级特性,如任务调度、线程优先级和异常处理。
|
3天前
|
安全 Java
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
|
3天前
|
安全 Java
【JAVA进阶篇教学】第六篇:Java线程中状态
【JAVA进阶篇教学】第六篇:Java线程中状态