学习多线程

本文介绍了Java中实现多线程的三种方式:继承Thread类、实现Runnable接口和实现Callable接口,并通过代码示例展示了具体实现。同时,讨论了线程同步的概念,包括同步代码块、同步方法以及使用Lock锁(ReentrantLock)进行线程同步,强调了同步在解决数据安全问题中的作用和优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实现多线程

        1.简单了解多线程

                答:是指从软件或者硬件上实现多个线程并发执行的技术

                  具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能

        2.并发和并行

                并行: 在同一时刻,有多个指令在多个cpu上同时执行

                并发: 在同一时间段,有多个指令在单个CPU上交替执行

        3.进程和线程

                1、进程:是正在运行的程序

                        独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位

                        动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的

                        并发性:任何进程都可以同其他进程一起并发执行

                2、线程:是进程中的单个顺序控制流,是一条执行路径

                        单线程:一个进程如果只有一条执行路径,则称为单线程程序

                        多线程:一个进程如果有多条执行路径,则称为多线程程序

        4、实现多线程方法一:继承Thread类

                1、方法介绍

                       

方法名说明
void run()在线程开启后,此方法将被调用执行
void start()使此线程开始执行,java虚拟机会调用run()方法

                2、实现步骤

                        1.定义一个类继承Thread类

                        2.在类中重写run()方法

                        3.创建类的对象

                        4.启动线程

                3、代码演示

public class Ticket extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName()+"卖出第"+i+"张票");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //创建实体对象
        Ticket t1 = new Ticket();
        //创建Thread类的对象,把实体对象作为构造方法的参数
        Thread su = new Thread(t1, "苏沐橙");
        Thread yan = new Thread(t1, "焰灵姬");
        //此线程开始启动
        su.start();
        yan.start();
    }
}

        5、实现多线程方法二:实现Runnable接口

                1、Thread构造方法

方法名说明
Thread()分配一个新的Thread对象

                2、实现步骤            

  • 定义一个类MyRunnable实现Runnable接口

  • 在MyRunnable类中重写run()方法

  • 创建MyRunnable类的对象

  • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数

  • 启动线程

                3、代码演示

                

public class Test2 {
    public static void main(String[] args) {
        Ticket2 t = new Ticket2();
        Thread thr = new Thread(t);
        //修改名字
        thr.setName("苏沐橙");
        //开启线程
        thr.start();
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName()+"卖出"+i+"张票");
        }
    }
}
public class Ticket2 implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName()+"卖出"+i+"张票");
        }
    }
}

        6、实现多线程方式三:实现Callable接口

                1、方法介绍

                        

方法名说明
call()计算结果,如果无法计算结果,则抛出一个异常
FutureTask()创建一个FutureTask,一但运行就执行给定的Callable
get()如有必要,等待计算完成,然后获取其结果

                2、实现步骤

                        1.定义一个类MyCallable实现Callable接口

                        2.在类中重写call()方法

                        3.创建类的对象

                        4.创建Future的实现类FutureTask对象,把类对象作为构造方法的参数

                        5.创建Thread类的对象,把FutureTask对象作为构造方法的参数

                        6.启动线程

                        7.在调用get方法,就可以获取线程结束之后的结果

                3、代码演示

public class Test3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Ticket3 t = new Ticket3();
        //可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象
        FutureTask<String> task = new FutureTask<String>(t);
        Thread tr = new Thread(task,"苏沐橙");
        tr.start();
        String s = task.get();
        System.out.println(s);

    }
}
public class Ticket3 implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName()+"你喜欢我吗?");
        }
        return "我喜欢你";
    }
}

        4、三种实现方式的对比

                1、实现Runnable,Callable接口

                        1.好处: 扩展性强,实现该接口的同时还可以继承其他的类

                        2.缺点:编程相对复杂,不能直接使用Thread类中的方法

                2、继承Thread类

                        1.好处:编程比较简单,可以直接使用Thread类中的方法

                        2.缺点:可以扩展性较差,不能再继承其他的类

        7、设置和获取线程名称

                1、方法介绍

方法名说明
void setName(String name)将此线程的名称更改为等于参数name
String getName()返回此线程的名称
Thread currentThread()返回对当前正在执行的线程对象的引用

                2、线程睡眠方法

方法名 说明
static void sleep(long millis) 使当前正在执行的线程睡眠指定的毫秒数

二、线程同步

        1、同步代码块解决数据安全问题

                1、安全问题出现的条件   

                       1.是多线程环境

                       2.有共享数据

                       3.有多条语句操作共享数据

                2、可以用同步代码块方法来解决

        2、同步代码块格式:

                synchronized(任意对象){

                      多线程语句操作共享数据

                }

        1、 synchronized(任意对象):就相当于给代码加了锁,任意对象可以看成是一把锁

         2、同步的好处和弊端

                好处:解决了多线程的数据安全问题

                弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

        2、代码演示

public class Ticket4 implements Runnable {

    private Object obj = new Object();

    private int tickets = 20;

    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                    tickets--;
                }
            }
        }
    }
}
public class Test4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Ticket4 t1 = new Ticket4();
        Thread tr = new Thread(t1, "苏沐橙");
        Thread tr2 = new Thread(t1, "焰灵姬");
        tr.start();
        tr2.start();

    }
}

        3、同步方法解决数据安全问题

                1、同步方法的格式:

                        同步方法:就是把synchronized关键字加到方法上

修饰符 synchronized 返回值类型 方法名(方法参数) {
    方法体;
}

        同步方法锁对象是:this

                2、静态同步方法

                        同步静态方法:就是把synchronized关键字加到静态方法上

修饰符 static synchronized 返回值类型 方法名(方法参数) {
    方法体;
}

                

同步静态方法的锁对象是: 类名.class

                 3、代码演示:

public class Ticket5 implements Runnable{

    private static int ticket = 20;


    @Override
    public void run() {
        while (true){
            if ("苏沐橙".equals(Thread.currentThread().getName())){
                //同步方法
                boolean b = synchronizedMode();
                if (b){
                    break;
                }
            }
            if ("焰灵姬".equals(Thread.currentThread().getName())) {
                synchronized (Ticket5.class){
                    if (ticket == 0){
                        break;
                    }else {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
                    }
                }
            }
        }
    }

    private static synchronized boolean synchronizedMode(){
        if (ticket==0){
            return true;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
            return false;
        }
    }
}

public class Test5 {
    public static void main(String[] args) {
        Ticket5 ti = new Ticket5();
        Thread tr = new Thread(ti, "苏沐橙");
        Thread tr2 = new Thread(ti, "焰灵姬");
        tr.start();
        tr2.start();
    }
}

三、lock锁

        虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

        1、ReentrantLock构造方法

                

方法名说明
ReentrantLock()创建一个ReentrantLock的实例

        2、加锁解锁方法

                

方法名说明
void lock()获得锁
void unlock()释放锁

        3、代码演示

public class Ticket5 implements Runnable{

    private static int ticket = 20;

    private static ReentrantLock lock = new ReentrantLock();


    @Override
    public void run() {
        while (true){
            if ("苏沐橙".equals(Thread.currentThread().getName())){
                //同步方法
                boolean b = synchronizedMode();
                if (b){
                    break;
                }
            }
            if ("焰灵姬".equals(Thread.currentThread().getName())) {
                synchronized (Ticket5.class){
                    if (ticket == 0){
                        break;
                    }else {
                        try {
                            lock.lock();
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
                    }
                }
            }
        }
    }

    private static synchronized boolean synchronizedMode(){
        if (ticket==0){
            return true;
        }else {
            try {
                lock.lock();
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
               lock.unlock();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
            return false;
        }
    }
}

public class Test5 {
    public static void main(String[] args) {
        Ticket5 ti = new Ticket5();
        Thread tr = new Thread(ti, "苏沐橙");
        Thread tr2 = new Thread(ti, "焰灵姬");
        tr.start();
        tr2.start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渣男あ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值