Java多线程JUC

本文介绍了Java多线程的相关概念,包括JUC工具包、线程与进程的区别、并发与并行的概念。详细讨论了线程的几种状态,并对比了wait和sleep方法的不同。此外,还分析了synchronized关键字和Lock接口在同步控制中的应用,以及它们的异同。最后,通过示例展示了如何使用synchronized实现线程安全的方法调用。
摘要由CSDN通过智能技术生成

以下讲的是在同一进程下多线程操作

什么是JUC

JUC就是java.util.concurrent工具包

线程和进程

进程:一个程序

一个进程可以包含多个线程,至少一个!

java默认包含两个线程:main、GC

线程:开一个进程,执行某个事物(线程负责)

对应Java而言实现线程:Thread、Runnable、Callable

java真的可以开启线程吗?否 ,只能通过本地方法去调用底层的C++,java无法直接操控硬件,是运行在虚拟机上的

并发和并行

并发(多线程操作同一个资源):CPU单核,CPU在多线程中快速切换,造成多线程的假象。从微观上还是单线程

并行(多个人一起行走):CPU多核,多个线程同时执行

线程有几个状态

可以查看源码 Thread类中public enum State {}方法

new(新生)

runnable(运行)

blocked(阻塞)

waiting(等待、死死的等)

timed_waiting(超时等待)

terminated(终止)

wait和sleep区别

1. 来自不同的类

wait => Object

sleep => Thread

2. 使用的范围不同

wait:必须在同步代码块中使用

sleep:可以在任何地方使用

3. 是否需要捕获异常

wait 不需要捕获异常

sleep 必须要捕获异常

Synchronized

synchronized是java中的关键字,一种同步锁。保证它修饰的代码块在同一时刻只有一个线程执行

public void saleTest(){
        //并发:多线程操作同一个资源类,三个线程同时卖票
        Ticket ticket = new Ticket();
        //lambda表达式  (参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "C").start();
 }


public class Ticket {

    //属性
    private int num = 100;

    //synchronized 本质:队列,锁
    public synchronized void sale() {
        if (num > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + (num--) + "张票,剩余:" + num);
        }
    }
}

 Lock

公平锁:十分公平,可以先来后到 。如果前面有个3h的线程,那么后面3s就要等3h

非公平锁:十分不公平,可以插队 (默认)

    public void saleTest(){
        //并发:多线程操作同一个资源类,三个线程同时卖票
        Ticket ticket = new Ticket();
        //lambda表达式  (参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(()->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "C").start();
    }

public class Ticket {

    //属性
    private int num = 100;
    //锁
    Lock lock = new ReentrantLock();


    public void sale() {
        //加锁
        lock.lock();
        try {
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了第" + (num--) + "张票,剩余:" + num);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //解锁
            lock.unlock();
        }
    }
}

 Synchronized和Lock区别

Synchronized 内置的关键字,Lock是一个Java类

Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁

Synchronized 会自动释放锁,Lock 必须要手动释放锁!如果不释放锁,会出现死锁

Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去

Synchronized 可重入锁,不可以中断,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置)

Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码

锁住的是谁?

 锁住的对象是方法的调用者

如果方法改成静态同步方法,那么锁住的就是 class 

以下用的是单元测试,在单元测试中,子线程中存在阻塞、死亡状态时,单元测试会立即停止所有子线程。所以在sendSms中睡2秒是无法看到后面的打印输出的,可以直接用main方法测试,就可以看到效果。

    /**
     * 中间睡1秒,很明显 先发短信
     */
    @Test
    public void phoneTest(){
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendSms();
        }, "A").start();
        try {
            //睡1秒
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        }, "B").start();
    }


public class Phone {

    public synchronized void sendSms() {
        System.out.println("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }
}
    /**
     * synchronized 锁住的对象是<方法的调用者>,锁住了phone对象
     * A线程先开始,先锁住了phone对象,先发短信
     */
    @Test
    public void phoneTest(){
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendSms();
        }, "A").start();
        try {
            //睡1秒
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        }, "B").start();
    }

public class Phone {

    public synchronized void sendSms() {
        try {
            //睡两秒
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }
}

未完待续。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值