【Java】JUC并发(线程的方法、多线程的同步并发)

线程的方法

一、线程的插队:join()方法

1、作用

暂停当前线程的执行,直到调用join()的目标线程执行完毕,但不影响同一时刻的其他线程。

java 复制代码
// 使用join()
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            System.out.println("子线程 => begin");

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println("子线程 => end");
        });

        t.start();

        // t线程插队到主线程(当前线程)前面
        // t线程结束后,主线程才会继续执行
        // t.join() 相当于 t.join(0 )
        t.join();
        System.out.println("主线程 => end");
    }
}

子线程 => begin
子线程 => end
主线程 => end

java 复制代码
// 不使用join()
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            System.out.println("子线程 => begin");

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println("子线程 => end");
        });

        t.start();

        // t线程插队到主线程(当前线程)前面
        // t线程结束后,主线程才会继续执行
        // t.join() 相当于 t.join(0 )
//        t.join();
        System.out.println("主线程 => end");
    }
}

主线程 => end
子线程 => begin
子线程 => end

2、重载形式

  • join() : 无限等待,直到目标线程终止
  • join(long millis):等待指定毫秒,超时不再等待
  • join(long millis, int nanos) :精确到纳秒,超时不再等待

3、使用场景(多个线程要求按序执行)

java 复制代码
public class Test02 {
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            for (int i = 0;i<5;i++){
                System.out.println(Thread.currentThread().getName() + "->" + i);
            }
        },"数字线程");

        Thread t2 = new Thread(()->{
            try {
                // 等待t1线程完成
                t1.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (char i = 'A';i<'E';i++){
                System.out.println(Thread.currentThread().getName() + "->" + i);
            }
        },"字母线程");

        Thread t3 = new Thread(()->{
            try {
                // 等待t2线程完成
                t2.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (char i = 'A';i<'E';i++){
                System.out.println(Thread.currentThread().getName() + "->" + (char)(Math.random()*100));
            }
        },"符号线程");

        t1.start();
        t2.start();
        t3.start();
    }
}

数字线程->0
数字线程->1
数字线程->2
数字线程->3
数字线程->4
字母线程->A
字母线程->B
字母线程->C
字母线程->D
符号线程->I
符号线程->&
符号线程->
符号线程->

4、join()和sleep()的区别

  • join()执行过程中,会释放当前线程的锁;sleep()执行过程中,不会释放当前线程的锁。
  • join()是用过wait/notify机制思想;sleep()通过操作系统的定时器来实现。
  • join()主要实现线程任务编排;sleep()用与模仿耗时操作。

二、线程的中断:interrupt()方法

1、作用

将该线程的中断状态设置为true,线程的下一步动作取决于中断状态。

2、实现原理

支持中断的方法(sleep()、join()、wait()等方法)在执行过程中,会监视中断状态,一旦发现其状态为"true",就会抛出一个中断异常InterruptedException,并给等待状态发出一个中断信号,从而退出等待状态。注意:当线程中没有可以监听中断状态的方法时,interrupt()方法将不起作用。

java 复制代码
public class Test03 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            // 场景1 : 调用休眠方法(支持中断方法)
            System.out.println("子线程开始执行!");
            try {
                // 子线程休眠4秒
                Thread.sleep(1000*4);
            } catch (InterruptedException e) {
                System.out.println("子线程中断!");
                return;
            }
            System.out.println("子线程结束!");
        });
        t.start();

        try {
            // 主线程休眠3秒
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        t.interrupt();
        System.out.println("主线程结束!");
    }
}

当子线程处于休眠状态时,而主线程对子线程进行中断则会子线程中断,不会继续向下执行。

子线程开始执行!
主线程结束!
子线程中断!

java 复制代码
public class Test03 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            // 场景2 : 判断线程的中断状态
            while (!isinterrupt){
                System.out.println("子线程开始执行!!");
            }

            System.out.println("子线程中断!");
        });
        t.start();
                try {
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        t.interrupt();
        System.out.println("主线程结束!");
    }
}

当没有使用中断方法时,子线程的中断状态一直时false,while的条件一
直为true会一直执行,当使用了中断方法后,中断状态更新为true,则会
退出while循环继续向下执行。

三、线程的让出:yield()方法

1、作用

让当前获取CPU的线程,主动让出CPU不执行。

java 复制代码
public class demo2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            public void run() {
                Thread.yield();
                for (int i = 0;i<5;i++){
                    System.out.println(i);
                }
            }
        };
        
        Thread t2 = new Thread(){
            public void run() {
                for (char i = 'A';i<'E';i++){
                    System.out.println(i);
                }
            }
        };
        
        t1.start();
        t2.start();
    }
}

四、守护线程(Daemon Thread)

1、用户线程和守护线程

用户线程:通常为创建的普通线程

守护线程:守护线程执行结束后,虚拟机不会自定退出;而非守护线程执行完毕后,虚拟机会自动退出

2、设置守护线程

在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程。

java 复制代码
Thread t1 = new Thread();
t1.setDaemon(true);
t1.start();

多线程同步并发

一、多线程的数据不一致

当多个线程同时运行时,线程的调度有操作系统决定,程序本身无法决定。因此,任何一个线程都有可能在任何指令出被系统暂停,然后莫个时间段后继续执行。如果多个线程同时共享一个资源,则会出现数据不一致的问题。

java 复制代码
public class Test04 {
    public static void main(String[] args) {
        Thread add = new Thread(new AddThread());
        Thread dec = new Thread(new DecThread());

        add.start();
        dec.start();

        try {
            add.join();
            dec.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Count.count);
        
    }
}
class Count{
    public static int count = 0; //公共的累加值
    public static Object lock = new Object(); // 锁对象
}

// 累加线程
class AddThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i<10000;i++){
                Count.count += 1;
            }
        }
    }
}
// 累减线程
class DecThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i<10000;i++){
                Count.count -= 1;
            }
        }
    }
}


由于算数运算没有原子性所以会出现算数运算被覆盖的情况,从而导致结果不正确
-1234

二、 synchronized关键字

1、什么是synchronized

Synchronized关键字,也可以理解为一种同步锁。他可以对一段代码进行加锁和解锁,从而使其拥有原子性,从而确保代码的线程安全。

2、synchronized 的用法

  • 修饰实例方法:synchronized 修饰实例方法,则用到的锁,默认为 this 当前方法调用对象;
java 复制代码
public class Test05 {
    public static void main(String[] args) {
        Foo f1 = new Foo();
        Foo f2 = new Foo();
        Thread t1 = new Thread(()->{
            f1.add();
        });

        Thread t2 = new Thread(()->{
            f1.dec();
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Foo.counter);
    }
}
class Foo{
    public static int counter = 0;

    public void add(){
        synchronized (this){
            for (int i = 0;i<10000;i++){
                counter++;
            }
        }
    }

    // 修饰实例方法,使用this关键字做锁
    public synchronized void dec(){
        for (int i=0;i<10000;i++){
            counter--;
        }
    }
}
  • 修饰静态方法:synchronized 修饰静态方法,则其所用的锁,默认为 Class 对象;
java 复制代码
public class Test05 {
    public static void main(String[] args) {
        Foo f1 = new Foo();
        Foo f2 = new Foo();
        Thread t1 = new Thread(()->{
            f1.add();
        });

        Thread t2 = new Thread(()->{
            f1.dec();
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Foo.counter);
    }
}
class Foo{
    public static int counter = 0;

    public void add(){
        synchronized (this.getClass()){
            for (int i = 0;i<10000;i++){
                counter++;
            }
        }
    }

    public synchronized static void dec(){
        for (int i=0;i<10000;i++){
            counter--;
        }
    }
}
  • 修饰代码块:synchronized 修饰代码块,则其所用的锁,是某个指定 Java 对象
java 复制代码
public class Test04 {
    public static void main(String[] args) {
        Thread add = new Thread(new AddThread());
        Thread dec = new Thread(new DecThread());

        add.start();
        dec.start();

        try {
            add.join();
            dec.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Count.count);

    }
}

class Count{
    public static int count = 0; //公共的累加值
    public static Object lock = new Object(); // 锁对象
}

// 累加线程
class AddThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i<10000;i++){
            // synchronized 同步锁
            synchronized (Count.lock) {// 加锁
                // 临界区
                Count.count += 1;
            }// 释放锁
        }
    }
}

// 累减线程
class DecThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i<10000;i++){
            // synchronized 同步锁
            synchronized (Count.lock) {// 加锁
                // 临界区
                Count.count -= 1;
            }// 释放锁
        }
    }
}
相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔4 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨6 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区8 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大9 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai9 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说9 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json