Java多线程之Thread和Runnable关于共享资源的对比

本文通过分析Thread和Runnable在处理共享资源时的不同实例,揭示了多线程中资源管理的关键因素并非由Thread或Runnable本身决定,而是由创建线程的方式。举例说明了如何通过共享对象实例来避免“重复卖票”问题,强调了正确管理和同步共享资源的重要性。

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

背景

Thread和Runnable关于共享资源的对比,网上看到很多不正确的结论如下:

Thread类创建多线程,无法保证多个线程对共享资源的正确操作,而Runnable接口可以保证多个线程对共享资源的正确访问。

得到这个结论的原因如下:

ThreadDemo 

package org.example.bk.multithread;


public class ThreadDemo {
    public static void main(String[] args) {
        // 1 看起来重复卖票
        new TicketWindow().start(); // 创建并开启第一个线程对象
        new TicketWindow().start(); // 创建并开启第二个线程对象
    }
}

class TicketWindow extends Thread {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) {
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

运行结果

 从结果中看到每张票都都卖了2次,出现了"重复卖票"的情况。

RunnableDemo 

package org.example.bk.multithread;


public class RunnableDemo {
    public static void main(String[] args) {        
        TicketWindow1 tw = new TicketWindow1();
        new Thread(tw, "窗口1").start(); // 创建线程对象并命名为窗口1,开启线程
        new Thread(tw, "窗口2").start(); // 创建线程对象并命名为窗口2,开启线程
    }
}

class TicketWindow1 implements Runnable {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) {
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

运行结果

 从结果来看,每张票只卖了1次。没有"重复卖票"的现象。

其实这种现象并不是Thread和Runnable的不同造成的,而是由于创建线程的方式不同造成的。

1. 从源码层面看Thread和Runnable,Thread实现了Runnable接口,实现多线程的本质还是Runnable接口。

2.造成"重复卖票"和"不重复卖票"的原因是什么呢?

"重复卖票"的原因分析:

ThreadDemo:new了两次TicketWindows对象,所以两个TickeWindow对象里面的tickets也是各自的变量,不是同一资源,自然在多线程时各自卖各自的tickets,自然能看到"重复卖票"的现象。

package org.example.bk.multithread;


public class ThreadDemo {
    public static void main(String[] args) {       
        new TicketWindow().start(); // 创建并开启第一个线程对象
        new TicketWindow().start(); // 创建并开启第二个线程对象
    }
}

class TicketWindow extends Thread {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) {
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

"不重复卖票"的原因分析:

RunnableDemo:只new了TicketWindow1对象1次。所以1个对象里的tickets只有1个变量,所以在多线程卖票时共享这个变量,自然不会出现"重复卖票"的现象。

package org.example.bk.multithread;


public class RunnableDemo {
    public static void main(String[] args) {        
        TicketWindow1 tw = new TicketWindow1();
        new Thread(tw, "窗口1").start(); // 创建线程对象并命名为窗口1,开启线程
        new Thread(tw, "窗口2").start(); // 创建线程对象并命名为窗口2,开启线程
    }
}

class TicketWindow1 implements Runnable {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) {
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

这里举反例进行说明

让Thread不重复卖票,让Runnable重复卖票。

ThreadDemo2

package org.example.bk.multithread;


public class ThreadDemo2 {
    public static void main(String[] args) {
        TicketWindow tw = new TicketWindow();
        Thread t1 = new Thread(tw,"窗口1");
        Thread t2 = new Thread(tw,"窗口2");
        t1.start();
        t2.start();
    }
}

class TicketWindow extends Thread {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) { 
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

运行结果

 从结果看到Thread方式可以"不重复卖票"。因为只new TicketWindow对象1次。

RunnableDemo2

package org.example.bk.multithread;


public class RunnableDemo2 {
    public static void main(String[] args) {
        TicketWindow1 tw1 = new TicketWindow1();
        TicketWindow1 tw2 = new TicketWindow1();
        Thread t1 = new Thread(tw1,"窗口1");
        Thread t2 = new Thread(tw2,"窗口2");
        t1.start();
        t2.start();
    }
}

class TicketWindow1 implements Runnable {
    private int tickets = 5;
    public void run() {
        while (tickets > 0) {
            Thread th = Thread.currentThread(); // 获取当前线程
            String th_name = th.getName(); // 获取当前线程的名字
            System.out.println(th_name + " 正在发售第 " + tickets-- + " 张票 ");
        }
    }
}

运行结果

 从运行结果看,Runnable也可以实现"重复卖票",因为new TicketWindow1对象2次。

综上所述

"重不重复卖票"现象并不是Thread和Runnable的不同造成的,而是由于创建线程的方式不同造成的。

完成!enjoy it!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值