多线程Thread类和Runnable接口资源共享问题分析
来源:互联网 发布:php零基础到项目实战 编辑:程序博客网 时间:2024/06/10 21:09
最近在看多线程时,一直迷茫为什么继承Thread类的多线程不能实现资源共享,但是实现Runnable接口的多线程却能实现资源共享,先看一段经典的卖票多线程,将程序修改一下,使运行结果直观。
首先是实现Runnable接口来实现多线程:
public class TicketSaleMain implements Runnable{ private int num = 5; //票数为5 public void run() { System.out.println(Thread.currentThread().getName() );//线程运行时先打印线程名称 for(int i=0; i<10; i++){ if(this.num>0){ //打印卖票信息 System.out.println(Thread.currentThread().getName() + "卖票: " + this.num--); } } } public static void main(String[] args) { TicketSaleMain ticketThread = new TicketSaleMain(); //声明了一个实现Runnable接口的对象A Thread th1 = new Thread(ticketThread); //线程一使用A th1.setName("窗口一"); Thread th2 = new Thread(ticketThread); //线程二使用A th2.setName("窗口二"); Thread th3 = new Thread(ticketThread); //线程三使用A th3.setName("窗口三"); th1.start(); th2.start(); th3.start(); }}
运行结果:
窗口二窗口一窗口二卖票: 5窗口一卖票: 4窗口二卖票: 3窗口一卖票: 2窗口二卖票: 1窗口三
因为3个线程共享了TicketSaleMain声明的放在堆里的对象ticketThread,都指向了这个对象,自然共享了成员属性num=5,相当于把一个任务塞到3个线程中,达到了一个卖票任务可以被3个线程共同执行,所以能达到资源共享,但是上述结果并不是一直一样顺序递减,还会有这样的结果1,
运行结果1:
窗口一窗口二窗口一卖票: 5窗口一卖票: 3窗口一卖票: 2窗口一卖票: 1窗口二卖票: 4窗口三
这是因为并发就是这样,如果你没有做并发控制,就会有各种灵异现象,因为线程执行是交错执行的。
也即,窗口一和窗口二分别先后执行一次this.num–后,窗口一执行了println,但是窗口二过了一阵子才执行了println。
还会有这样的结果2:
运行结果2:
窗口一窗口二窗口二卖票: 5窗口一卖票: 5窗口三窗口二卖票: 4窗口三卖票: 2窗口一卖票: 3窗口二卖票: 1
窗口一和窗口二分别同时执行一次this.num–后,一起执行println造成,这种情况在执行了很多次才会出现一次,如果想要更明显,可以修改run方法如下:
public void run() { System.out.println(Thread.currentThread().getName() );//线程运行时先打印线程名称 for(int i=0; i<10; i++){ try { Thread.sleep(1000); //让线程执行的时候休眠1000ms } catch (InterruptedException e) { e.printStackTrace(); } if(this.num>0){ //打印卖票信息 System.out.println(Thread.currentThread().getName() + "卖票: " + this.num--); } } }
运行结果:
窗口二窗口一窗口三窗口二卖票: 5窗口三卖票: 4窗口一卖票: 3窗口二卖票: 2窗口三卖票: 1窗口一卖票: 1
上述这些情况都是因为没有对多线程进行并发控制,需要对线程进行同步操作,避免线程对资源竞争,防止出现线程安全问题,同步操作使得在同一个时间段内只有一个线程能进行System.out.println(Thread.currentThread().getName() + "卖票: " + this.num--);
其余线程必须等待此线程完成后才能继续执行。
在此我们用synchronized关键字来同步,synchronized关键字可以同步方法,也可以同步代码块。
同步方法,就是可以把for循环内的代码封装成一个方法booking(),并用public synchronized void声明,然后再run()中调用booking方法
同步代码块,可以用synchronized (this) { }将for循环后的代码块包起来,以此来进行同步控制。
然后是继承Thread类来实现多线程,在此就不多说了,直接上代码:
public class TicketSaleMain extends Thread private int num = 5; //总共票数设定为5张 @Override public void run() { System.out.println(Thread.currentThread().getName() ); //线程运行时先打印线程名称 for(int i=0; i<10; i++){ if(this.num>0){ //打印卖票信息 System.out.println(Thread.currentThread().getName() + "卖票: " + this.num--); } }}public static void main(String[] args) { TicketSaleMain th1 = new TicketSaleMain(); //声明的对象线程一 th1.setName("窗口一"); TicketSaleMain th2 = new TicketSaleMain(); //声明的对象线程二 th2.setName("窗口二"); TicketSaleMain th3 = new TicketSaleMain(); //声明的对象线程三 th3.setName("窗口三"); //分别启动三个线程 th1.start(); th2.start(); th3.start(); }}
运行结果:
窗口二窗口一窗口二卖票: 5窗口二卖票: 4窗口二卖票: 3窗口二卖票: 2窗口二卖票: 1窗口一卖票: 5窗口三窗口一卖票: 4窗口三卖票: 5窗口一卖票: 3窗口三卖票: 4窗口一卖票: 2窗口三卖票: 3窗口一卖票: 1窗口三卖票: 2窗口三卖票: 1
从运行结果看,继承Thread类实现多线程,几个线程就要声明几个对象,每个对象都绑定了num=5,相当于每个卖票任务都绑定了一个线程,每个线程执行的卖票任务不是同一个,因此没有实现资源共享。
- 多线程Thread类和Runnable接口资源共享问题分析
- 多线程Thread类和Runnable接口
- Java 多线程之 Runnable VS Thread 及其资源共享问题
- 多线程-利用thread类和runnable接口实现多线程
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口(转载)
- Java 多线程的Thread类和Runnable接口
- Java 多线程的Thread类和Runnable接口
- 多线程的使用——Thread类和Runnable接口
- java中多线程Runnable接口和Thread类的区别
- java多线程(一)-Thread类和Runnable接口
- 04.多线程--07.【Runnable接口的来历】【Thread类和Runnable接口的关系】【个人总结】
- 多线程 Thread 和Runnable
- 多线程Thread和Runnable
- GSS4 - Can you answer these queries IV
- Liblinphone 3.9.1中文--Modules--Managing call logs
- iOS动画进阶 - 手摸手教你写 Slack 的 Loading 动画
- 连续子数组的最大和
- 关于synchronized与lock的性能比较
- 多线程Thread类和Runnable接口资源共享问题分析
- WinPcap编程入门(1)——获取本地适配器信息
- android中tools的含义及用法
- 启动另一个Activity并利用Intent传输数据
- linux 远程连接mysql数据库
- Oracledbconsoleorcl启动不了,本地连接数据库失败
- iOS那些简单的动画,属性详解和转场动画
- Android文字跑马灯控件(文本自动滚动控件,左右移动 带源码)
- Handler