多线程实现方式二

发布时间:2024年01月15日

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();
    }
}
文章来源:https://blog.csdn.net/2301_81153022/article/details/135578537
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。