zoukankan      html  css  js  c++  java
  • java

    线程安全:

    单线程操作,没有并发,一般是早期版本方法

    StringBuffer

    Vector

    HashTable

    线程非安全:

    多线程并发,一般是新版本方法,提高了效率,但是带来了多线程的问题。

    StringBuilder

    ArrayList

    HashMap

    线程运行顺序主要依靠电脑CPU自动进行分配,我们只能用一些方法来间接控制一些特殊情况,主要还是靠CPU自己分配资源。

    线程的状态:

    创建线程(线程存在) - 就绪状态(可以执行,等待CPU分配资源,获得资源后开始运行) - 执行状态(运行线程,开始工作执行代码) - 等待/挂起(cpu给的资源用完了,或者我们停了它以便执行其他线程,等待结束后回到就绪状态) - 异常/死亡(出现exception,或者停止)

    创建线程: new Thread

    就绪状态:start()

    执行状态:run()  //cpu自动执行,如果手动执行则会先把它运行完后再执行其他的线程(变成单线程)

    等待/挂起:wait()   ---》 notify,notifyAll 方法唤醒后返回就绪状态

    异常/死亡:抛出异常Exception,或者人为强制结束(以前用stop,现在已经过时了),线程结束

    线程的实现:

    定义一个类

    继承Thread类(java中的线程类)

    重写run方法

    new 线程对象(创建线程),进入就绪状态。

    然后就等着CPU有时间了来分配资源(有时候也有高大上的叫时间碎片一类的=。=)处理它。

    然后等他自动运行完或者我们用一些方法比如sleep一类的控制它的运行。

    这里只介绍基础实现

    package thread;
    
    public class ThreadTest {
        public static void main(String[] args){
    
            //首先,下面三个例子不要同时运行,会9个线程并发看不清效果
            //每次3个线程一起运行就可以了
    
            //用到的class:Sporter
            //创建线程
            Sporter s1 = new Sporter("博尔特");
            Sporter s2 = new Sporter("刘翔");
            Sporter s3 = new Sporter("苏炳添");
            //就绪状态
            s1.start();
            s2.start();
            s3.start();
            //执行状态
            //线程的执行由CPU进行管理,我们不能直接控制,CPU有资源后会进行分配并让线程执行。
            //博尔特跑到第0米了
            //博尔特跑到第1米了
            //博尔特跑到第2米了
            //博尔特跑到第3米了
            //博尔特跑到第4米了
            //博尔特跑到第5米了
            //博尔特跑到第6米了
            //博尔特跑到第7米了
            //博尔特跑到第8米了
            //博尔特跑到第9米了
            //博尔特跑到第10米了
            //博尔特跑到第11米了
            //博尔特跑到第12米了
            //博尔特跑到第13米了
            //博尔特跑到第14米了
            //刘翔跑到第0米了
            //刘翔跑到第1米了
            //刘翔跑到第2米了
            //...
            //根据电脑性能结果不同(电脑越好的连续执行一个对象的次数越多),同一台电脑每次执行结果也不同。
            //通过结果可以知道CPU在执行完一个线程的一部分后会执行其他线程,多线程交错运行
            //-。-我之前一直以为多线程就是多个线程一起执行。。。现在看来只是逻辑上多线程,其实还是一根线。。。
    
            System.out.println("-------------------------我是华丽的分界线1---------------------------------");
            //用到的class:Runner
    
            //创建线程
            Runner r1 = new Runner("博尔特");
            Runner r2 = new Runner("刘翔");
            Runner r3 = new Runner("苏炳添");
    
            Thread t1 = new Thread(r1);//start等方法都是Thread中的,Runnable接口中没有,所以需要把对象通过Thread的构造方法变成Thread线程
            Thread t2 = new Thread(r2);
            Thread t3 = new Thread(r3);
            //就绪状态
            t1.start();
            t2.start();
            t3.start();
            //执行状态
            //执行结果与直接继承Thread类的方法创建的线程类似。
    
            System.out.println("-------------------------我是华丽的分界线2---------------------------------");
            //12306火车票售票系统
            //用到的class:TicketWindow,System12306,Ticket
            TicketWindow tw1 = new TicketWindow("售票窗口1");
            TicketWindow tw2 = new TicketWindow("售票窗口2");
            TicketWindow tw3 = new TicketWindow("售票窗口3");
    
            tw1.start();
            tw2.start();
            tw3.start();
    
            //只截取了最后几行
            //售票窗口3售出了一张:从ShangHai51到BeiJing51价格为400.0的车票
            //售票窗口1售出了一张:从ShangHai93到BeiJing93价格为400.0的车票
            //售票窗口2售出了一张:从ShangHai92到BeiJing92价格为400.0的车票
            //售票窗口1售出了一张:从ShangHai95到BeiJing95价格为400.0的车票
            //售票窗口3售出了一张:从ShangHai94到BeiJing94价格为400.0的车票
            //售票窗口1售出了一张:从ShangHai97到BeiJing97价格为400.0的车票
            //售票窗口2售出了一张:从ShangHai96到BeiJing96价格为400.0的车票
            //售票窗口1售出了一张:从ShangHai99到BeiJing99价格为400.0的车票
            //售票窗口3售出了一张:从ShangHai98到BeiJing98价格为400.0的车票
            //对不起,售票窗口3票已售完
            //对不起,售票窗口2票已售完
            //对不起,售票窗口1票已售完
    
        }
    
    }

    class Sporter

    package thread;
    
    public class Sporter extends Thread {
        private String name;
    
        public Sporter(){}
    
        public Sporter(String name){
            this.name = name;
        }
    
        public void run(){ //重写run方法
            for(int i = 0; i < 100; i++) {  //用来显示线程进程
                System.out.println( name + "跑到第" + i + "米了");
    
            }
        }
    }

    class Runner

    package thread;
    
    public class Runner implements Runnable { //Runnable 是个接口,里面只有run一个抽象方法,主要作用是告诉程序这个类可以作为线程,类似于Serilizable,这样这个类就可以继承其他类了(java每个类只能有一个父类,但是可以继承多个接口)
        private String name;
    
        public Runner(){}
    
        public Runner(String name){
            this.name = name;
        }
    
        public void run(){ //重写run方法
            for(int i = 0; i < 100; i++) {  //用来显示线程进程
                System.out.println( name + "跑到第" + i + "米了");
            }
        }
    }

    class System12306

    package thread;
    
    import java.util.ArrayList;
    import java.util.Vector;
    
    //表示12306系统
    //因为系统唯一,所以用单例模式设计
    //单例模式的笔记:https://www.cnblogs.com/clamp7724/p/11604422.html
    public class System12306 {
        //单例模式,全世界只有这一个系统,可以直接调
        // 这里假设只有这一个车次,真实情况肯定更复杂一些
    
        private System12306(){} //构造函数私有化。
        private static System12306 sys = new System12306();//所有外部类只能操作这一个对象。
        public static System12306 getInstance(){ //给一个接口可以用外部创建对象访问这个类(不管创建多少个访问的其实是同一个对象,达到单例模式效果)
            return sys;
        }
    
        //存票用的数组(容器)
        private Vector<Ticket> tickerts = new Vector<>(); //因为对象只有一个所以static加不加都行。
        //Vector方法自带synchronized(同步:两个地方不能同时运行这个对象,虽然修饰的是方法,但是锁定的是对象),是ArrayList的早期版本,线程安全,效率较低。
    
        {   //块,会在构造函数运行前运行,大学学的是在所有构造方法里加一遍。。。
            for(int i = 0; i < 100; i++){ //假设这次有100张票
                tickerts.add(new Ticket("ShangHai" + i, "BeiJing" + i, 400.0f));//加个i方便观察
            }
        }
    
        //出票
        public Ticket getTickert() {
            try {
                return tickerts.remove(0);//每次把链表第一个票删掉并返回
            }catch (Exception e){ //如果没票了,可能会抛出异常,这时返回null。   也可以在前面加个if判断,if(tickerts.size() == 0){return null}
                return null;
            }
        }
    }

    class TicketWindow

    package thread;
    
    //多个窗口卖火车票用来演示多线程
    public class TicketWindow extends Thread{//需要继承Thread类
        private String windowName;
    
        public TicketWindow(String windowName){
            this.windowName = windowName;
        }
    
        public void run(){ //重写run方法,用来控制运行的时候干什么
            sellTicket();  //运行的时候不停卖票
        }
    
        public void sellTicket(){
            while(true){
                System12306 s = System12306.getInstance();//获取12306对象
                Ticket t = s.getTickert();//因为是Vector线程安全,所以不用加锁一类的防止多线程冲突。
                if(t == null){
                    System.out.println("对不起," + windowName + "票已售完");
                    break;
                }
                else{
                    System.out.println(windowName + "售出了一张:" + t); //重写了toString方法,所以可以直接输出对象 t 的内容
                }
            }
        }
    
    
        public String getWindowName() {
            return windowName;
        }
    
        public void setWindowName(String windowName) {
            this.windowName = windowName;
        }
    }

    class Ticket

    package thread;
    
    //用来储存火车票的信息
    public class Ticket {
        private String startStation;
        private String endStation;
        private Float price = null;
        //补充:如果一个类只是拿来当一个容器,并没有特殊作用(只有属性和一些简单的方法,一般拿来对应储存数据库表中的数据),叫POJO类或者JavaBean。
        //- -之前网上各种说JavaBean什么的,其实就是这种类。。。
        //而数据库中有可能出现null值,如果拿float这种基本类型储存会报错,所以一般用对应的class来储存。class储存也可以直接赋值,而且程序健壮性更强。
        //8个基本类:             byte,short,int,long,float,double,boolean,char
        //8个基本类对应的class:  Byte,Short,Integer,Long,Float,Double,Boolean,Character
    
        public Ticket(){
        }
    
        public Ticket(String startStation, String endStation, Float price){
            this.startStation = startStation;
            this.endStation = endStation;
            this.price = price;
        }
    
        public String toString(){ //重写toString方法,方便打印。   System.out.println()中直接写对象名时默认调用的是toString方法
            return "从" + startStation + "到" + endStation + "价格为" + price + "的车票";
        }
    
        //右键 --- Generate --- get and set ---选中要创建的属性,可以自动生成get和set方法
        public String getStartStation() {
            return startStation;
        }
    
        public void setStartStation(String startStation) {
            this.startStation = startStation;
        }
    
        public String getEndStation() {
            return endStation;
        }
    
        public void setEndStation(String endStation) {
            this.endStation = endStation;
        }
    
        public Float getPrice() {
            return price;
        }
    
        public void setPrice(Float price) {
            this.price = price;
        }
    }

                                                                                                                                                                                                                                     

  • 相关阅读:
    10.16作业
    day0402作业
    day04作业
    10.13作业
    JVM原理最全、清晰、通俗讲解
    Java的SimpleDateFormat,DateTimeFormatter:YYYY与yyyy
    从源码层面理解 ArrayList 扩容策略
    哈夫曼树
    面向对象三大基本特性,五大基本原则
    数据结构
  • 原文地址:https://www.cnblogs.com/clamp7724/p/11648308.html
Copyright © 2011-2022 走看看