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

相关文章
|
5天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
4天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
4天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
3天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
9天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
32 9
|
6天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
12天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
9天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
12天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
26 3
|
11天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
下一篇
无影云桌面