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月前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
271 0
|
2月前
|
Java API 容器
Java基础学习day08-2
本节讲解Java方法引用与常用API,包括静态、实例、特定类型方法及构造器引用的格式与使用场景,并结合代码示例深入解析。同时介绍String和ArrayList的核心方法及其实际应用。
153 1
|
1月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
204 0
|
1月前
|
负载均衡 Java API
grpc-java 架构学习指南
本指南系统解析 grpc-java 架构,涵盖分层设计、核心流程与源码结构,结合实战路径与调试技巧,助你从入门到精通,掌握高性能 RPC 开发精髓。
253 7
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
153 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
168 1
|
2月前
|
Java
Java基础学习day08-作业
本作业涵盖Java中Lambda表达式的应用,包括Runnable与Comparator接口的简化实现、自定义函数式接口NumberProcessor进行加减乘及最大值操作,以及通过IntProcessor处理整数数组,实现遍历、平方和奇偶判断等功能,强化函数式编程实践。
75 5
|
2月前
|
Java 程序员
Java基础学习day08
本节讲解Java中的代码块(静态与实例)及其作用,深入介绍内部类(成员、静态、局部及匿名)的定义与使用,并引入函数式编程思想,重点阐述Lambda表达式及其在简化匿名内部类中的应用。
138 5
|
2月前
|
Java
Java基础学习day07-作业
本作业包含六个Java编程案例:1)动物类继承与多态;2)加油卡支付系统;3)员工管理类设计;4)学生信息统计接口;5)USB设备控制;6)家电智能控制。综合运用抽象类、接口、继承、多态等面向对象技术,强化Java基础编程能力。
175 3
|
2月前
|
Java
Java基础学习day06-作业
本内容为Java基础学习作业,涵盖两个案例:一是通过Card类及其子类GoldenCard、SilverCard实现加油卡系统,体现封装与继承;二是通过Shape类及子类Circle、Rectangle演示多态与方法重写,强化面向对象编程理解。
80 1

热门文章

最新文章