【线程实现的两种方式及区别】

我们来用最经典的卖票的案例,表明两种实现方式的区别,同时分析线程不安全产生的原因

一、继承Thread类

package test;

/**
 * @Description
 * @Author shusheng
 * @Email [email protected]
 * @Date 2018/8/31
 */
public class SellTicketOne extends Thread{

    private static int tickets = 100;

    @Override
    public void run(){
        while(true){
            if(tickets>0){
                System.out.println(getName()+"正在出售第"+tickets+"张票");
                tickets--;
            }
        }
    }

}

二、实现Runnable接口

package test;

/**
 * @Description
 * @Author shusheng
 * @Email [email protected]
 * @Date 2018/8/31
 */
public class SellTicketTwo implements Runnable{

    private static int tickets = 100;

    @Override
    public void run(){
        while(true){
            if(tickets>0){
                System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
                tickets--;
            }
        }
    }

}

启动线程

package test;

/**
 * @Description
 * @Author shusheng
 * @Email [email protected]
 * @Date 2018/8/31
 */
public class SellTicketTest {

    public static void main(String[] args) {

        SellTicketOne one1 = new SellTicketOne();
        SellTicketOne one2 = new SellTicketOne();
        SellTicketOne one3 = new SellTicketOne();
        one1.setName("窗口一");
        one2.setName("窗口二");
        one3.setName("窗口三");
        one1.start();
        one2.start();
        one3.start();

        SellTicketTwo two = new SellTicketTwo();
        Thread t1 = new Thread(two,"窗口四");
        Thread t2 = new Thread(two,"窗口五");
        Thread t3 = new Thread(two,"窗口六");
        t1.start();
        t2.start();
        t3.start();

    }
}

可以看到,二者的主要区别是:

1.实现Runnable接口的方式可以避免由于JAVA单继承带来局限性

2.实现Runnable接口的方式,适用多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码、数据有效分离,较好的体现了面向对象的设计思想。

加上每次卖票延迟200毫秒,运行程序,发现两个问题:

A:相同的票卖了多次:CPU的一次操作必须是原子性

B:出现了负数票:随机性和延迟导致的

原文地址:https://www.cnblogs.com/zuixinxian/p/9565888.html

时间: 2024-10-13 17:27:05

【线程实现的两种方式及区别】的相关文章

Java并发编程-创建线程的两种方式及区别

转载请注明:http://blog.csdn.net/UniKylin/article/details/45016117 1.线程和进程的区别 并行:是多个任务在同一时间同时执行,例如多核计算机同时计算的任务可以理解为并行 并发:从微观上看是多个任务抢占一个CPU从而执行自己的任务,轮流执行任务,但是如果遇到资源冲突的时候并没有从根本提高执行效率.但是提高了CPU的使用效率. 前段时间在GitHub上的一幅图可以很好的阐述上面的概念非常形象 2.Java中创建线程的两种方式 1.第一种方式:直接

Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载

 在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新.在数据量非常大的情况下,我们通常会使用两种技术来进行异步加载,一是通过AsyncTask来实现,另一种方式则是通过ThreadPool来实现,今天我们就通过一个例子来讲解和对比这两种实现方式.     项目的结构如下所示:     在今天这个例子里,我们用到了之前一篇文章中写过的一个自定义控件,如果有同学感兴趣的话可以点击这里来先研究下这个控件的实现,为了配合异

关于线程开启的两种方式

第一种方式,继承Thread类 1 public class Thread extends java.lang.Thread { 2 3 private String name; 4 5 // 定义run方法 6 public void run() { 7 for (int i = 0; i < 20; i++) { 8 System.out.println(name + "haha"); 9 } 10 } 11 12 // 构造函数重写构(无参) 13 public Threa

docker容器实现数据持久化的两种方式及其区别

前言 这篇博文是我对docker实现数据持久化几种方式的特征进行一个总结. 在docker中,它的存储文件系统是在dockerhost上原有的xfs或ext4架设了一层文件系统:overlay2(将此行重点标注的原因就是我在面试中被问到过:docker使用的是什么文件系统?),通过docker info命令可以查看出主机上docker相关的信息,包括支持的网络类型.系统版本.内核版本.docker主机的cpu.内存等信息.如下: 在docker中实现数据持久化有两种方式:Bind mount和D

JAVA中创建字符串的两种方式的区别

我们知道,通常在Java中创建一个字符串会有两种方式,通过双引号直接赋值和通过构造器来创建. String x = "abcd"; String y = new String("abcd"); 然而,这两种方式之间的区别是什么?分别应用于哪些情况,之前还不是很懂. 1.双引号的方式 String x = "abcd"; String y = "abcd"; System.out.println(x==y);//true Sys

vue 路由传参 params 与 query两种方式的区别

初学vue的时候,不知道如何在方法中跳转界面并传参,百度过后,了解到两种方式,params 与 query.然后,错误就这么来了:  router文件下index.js里面,是这么定义路由的: { path:"/detail", name:"detail", component:home } 我想用params来传参,是这么写的,嗯~ this.$router.push({ path:"/detail", params:{ name:'nameV

js对象中属性调用.和[] 两种方式的区别

JS 调用属性一般有两种方法——点和中括号的方法. 标准格式是对象.属性(不带双引号),注意一点的是:js对象的属性,key标准是不用加引号的,加也可以,特别的情况必须加,如果key数字啊,表达式啊等等. 加引号是为了将其视为整体,认识一点:从对象角度,属性是不加引号的,如name,"name"这是啥,属性不可能是“name”,所以即使加了双引号,对象调用时还是要去掉引号的 例如 使用.方法 var obj = { name: "cedric" } console.

UIImage创建图片的两种方式的区别

在工作中经常会遇到添加图片,用哪种方式添加更好呢?请看详解 方法一: UIImage *image = [UIImage imageNamed:@"haha"]; 这种方法创建的图片是从缓存中获取的,程序会先从缓存中查找是否有这张图片,如果有的话就加载,如果没有的话,会将图片添加到缓存再使用.这样的创建方式一般用于经常使用的使用,因为从缓存中添加图片会更快一些,节省时间.但是缺点是一旦添加到缓存中就不会被释放,如果图很多很大需要占用很多很大的内存空间. 方式二: NSString *p

Android更新主线程UI的两种方式handler与runOnUiThread()

在android开发过程中,耗时操作我们会放在子线程中去执行,而更新UI是要主线程(也叫做:UI线程)来更新的,自然会遇到如何更新主线程UI的问题.如果在主线程之外的线程中直接更新页面显示常会报错.抛出异常:android.view.ViewRoot.CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 为什么要有handler机制?h