多线程实现方式二

本文详细介绍了如何使用Runnable接口实现多线程,以及线程同步的重要性,通过实例演示了如何使用`synchronized`关键字和`ReentrantLock`进行线程同步,以确保在卖票场景中的线程安全。
摘要由CSDN通过智能技术生成

Runnable

Runable接口实现多线程

  • 实现 Runnable 接口

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

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

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

    • 启动线程

demo:

定义一个类作为Runnable接口实现类

package com.itxs.demo05;

/**
 * @Classname : MyRunnable
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + " i = " + i);
        }
    }
}

测试类demo01

package com.itxs.demo05;

/**
 * @Classname : demo01
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class demo01 {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        //创建线程
        Thread mt01 = new Thread(mr, "线程01");//Runnable接口实现类对象作为参数进行传递
        Thread mt02 = new Thread(mr, "线程02");
        Thread mt03 = new Thread(mr, "线程03");
        //匿名内部类方式实现
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    System.out.println(Thread.currentThread().getName()+" i = " + i);
                }
            }
        },"匿名线程").start();
        // 线程开启
        mt01.start();
        mt02.start();
        mt03.start();
    }
}

使用Runnable接口实现多线程的好处

  • 相比继承 Thread 类,实现 Runnable 接口的好处

    • 避免了 Java 单继承的局限性

    • 适合多个程序的代码同时处理一个资源的情况,把线程和程序的代码、数据有效的分离,较好的体现了面向对象程序设计的思想

线程同步 - 三个窗口买票

需求:德云社封箱演出共有 100 张门票,设置三个窗口买票,设计模拟买票的程序

思路:

  1. 定义一个 SellTickets 实现 Runnable 接口,里面定义一个成员:private int tickets = 100;

  2. 在 SellTickets 类中重写 run() 方法,实现买票

    1. 判断剩余票数是否大于 0,是就卖,并告知是哪个窗口卖出的

    2. 卖掉一张之后要对应减一

    3. 没有票了,也可能有人来买,用死循环让买票动作一直持续

  3. 顶一个测试类 SellTicketsTest,里面有 main() 方法

    1. 创建 SellTickets 类对象

    2. 创建三个 Thread 类的对象,把 SellTickets 对象作为构造方法的参数,并给出对应的窗口名称

    3. 启动线程

sycnchronized(任意对象){}:同步语句块,多个线程操作同一个资源时,当某个线程执行同步语句块里面的代码时,别的线程是无法执行的,只有当执行同步语句块线程执行完里面同步语句块的内容时,其他线程才能进行访问

  • 是否有多线程环境

  • 是否有共享数据

  • 是否有多条语句操作共享项数据

参考文章

demo:

卖票的动作,注意同步语句块的用法

package com.itxs.demo06;

/**
 * @Classname : SellTickets
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class SellTickets implements Runnable {

    private int tickets = 100;// 门票数量为100

    @Override
    public void run() {
        // 定义死循环,一直进行买票
        while (true){
            // 同步语句块,一个窗口抢到卖票权,其他窗口无法卖出同一个票
            synchronized (this){
                // 判断门票数是否大于0满足条件进行卖票
                if(tickets > 0){
                    //打印出票
                    System.out.println(Thread.currentThread().getName() +"正在买第 - "+this.tickets+"张门票");
                    // 每次打印出票后,票数减去1
                    this.tickets --;
                }
            }
            // 每个窗口卖出票后,等待出票
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

test测试类

package com.itxs.demo06;

/**
 * @Classname : test
 * @Description : TODO 测试类
 * @Author : lin_refuel@qq.com
 */
public class test {
    public static void main(String[] args) {
         //创建卖票动作的线程
        SellTickets st = new SellTickets();
        // 创建三个窗口进行买票
        Thread windows01 = new Thread(st, "窗口1");
        Thread windows02 = new Thread(st, "窗口2");
        Thread windows03 = new Thread(st, "窗口3");
        // 开始买票
        windows01.start();
        windows02.start();
        windows03.start();
    }
}

lock实现同步锁

还是上面的案例,通过lock方式实现线程同步

买票的类

package com.itxs.demo06;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Classname : SellTickets
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class SellTickets implements Runnable {

    private int tickets = 100;// 门票数量为100
    private  Lock lock = new ReentrantLock();

    @Override
    public void run() {
        // 定义死循环,一直进行买票
        while (true){
            // 同步语句块,一个窗口抢到卖票权,其他窗口无法卖出同一个票
            ticket();
            // 每个窗口卖出票后,等待出票
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 同步方法
    private /*synchronized*/ void ticket() {
        //synchronized (this){
        lock.lock();//上锁
            // 判断门票数是否大于0满足条件进行卖票
            if(this.tickets > 0){
                //打印出票
                System.out.println(Thread.currentThread().getName() +"正在买第 - "+this.tickets+"张门票");
                // 每次打印出票后,票数减去1
                this.tickets --;
            }
        //}
        lock.unlock();//开锁,!!!注意不要忘记开锁
    }
}

test测试类

package com.itxs.demo06;

/**
 * @Classname : test
 * @Description : TODO 测试类
 * @Author : lin_refuel@qq.com
 */
public class test {
    public static void main(String[] args) {
         //创建卖票动作的线程
        SellTickets st = new SellTickets();
        // 创建三个窗口进行买票
        Thread windows01 = new Thread(st, "窗口1");
        Thread windows02 = new Thread(st, "窗口2");
        Thread windows03 = new Thread(st, "窗口3");
        // 开始买票
        windows01.start();
        windows02.start();
        windows03.start();
    }
}
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现多线程有以下几种方式: 1. 继承Thread类:创建一个继承自Thread类的子类,并重写其run()方法来定义线程的执行逻辑。然后通过创建子类的实例并调用start()方法来启动线程。 ```java class MyThread extends Thread { public void run() { // 线程执行逻辑 } } // 创建线程实例并启动 MyThread thread = new MyThread(); thread.start(); ``` 2. 实现Runnable接口:创建一个实现了Runnable接口的类,并实现其run()方法。然后通过创建该类的实例,并将其作为参数传递给Thread类的构造函数来创建线程对象。 ```java class MyRunnable implements Runnable { public void run() { // 线程执行逻辑 } } // 创建线程实例并启动 MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); ``` 3. 使用Callable和Future:创建一个实现了Callable接口的类,并实现其call()方法。然后通过创建该类的实例,并将其作为参数传递给ExecutorService的submit()方法来提交任务,并返回一个Future对象,通过该对象可以获取任务的执行结果。 ```java import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; class MyCallable implements Callable<Integer> { public Integer call() { // 线程执行逻辑 return 1; } } // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(1); // 提交任务并获取Future对象 MyCallable callable = new MyCallable(); Future<Integer> future = executor.submit(callable); // 获取任务的执行结果 try { Integer result = future.get(); // 处理结果 } catch (Exception e) { // 异常处理 } finally { // 关闭线程池 executor.shutdown(); } ``` 以上是Java实现多线程的几种方式。你可以根据具体的需求选择适合的方式实现多线程功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值