Java小白学点东西(16)(几个常用类)

1.常用类

1.1Date

Date专门处理日期

这个类即将被弃用,官方手册里面说会有其他类代替     Calendar类来代替

​
import java.util.Date;
​
public class Demo1 {
​
    public static void main(String[] args) {
        //1.实例化Date对象
        Date date = new Date();
        //Tue Aug 17 09:37:55 CST 2021 这个时间是不友好的
        System.out.println(date);
        Date date1 = new Date(2000, 10,5);//已经被弃用
        System.out.println(date1);
        
        //Tue Aug 17 09:42:02 CST 2021
        //System.currentTimeMillis()  时间戳 1970以后的
        Date date2 = new Date(System.currentTimeMillis());
        System.out.println(date2);
        
        System.out.println(date2.getYear() + 1900);
        System.out.println(date2.getMonth() + 1);//0代表1月  7月代表8月
        
    }
}
​

1.2Calendar类

专门出来时间日期的一个类

Calendar是一个抽象类,不能直接实例化,但是官方手册告诉我们如何把对象创建出来

  • CalendargetInstance方法返回一个Calendar对象,其日历字段已使用当前日期和时间进行初始化:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Demo5 {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        System.out.println(calendar.get(calendar.YEAR));
        System.out.println(calendar.get(calendar.MONTH)+1);//因为在封装的时候 从0开始的,所以月份需要加1
        System.out.println(calendar.get(calendar.DATE));

        System.out.println(calendar.get(calendar.DAY_OF_MONTH));
        System.out.println(calendar.get(calendar.DAY_OF_WEEK)-1);//老外是将周日看成咱们的周一,所以中国来算的话需要减一
        System.out.println(calendar.get(calendar.DAY_OF_YEAR));

        System.out.println(calendar.get(calendar.HOUR));//默认12小时计时法
        System.out.println(calendar.get(calendar.MINUTE));
        System.out.println(calendar.get(calendar.SECOND));

        Date date = calendar.getTime();//获取时间
        System.out.println(date); //英文的很不友好 看不懂

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        System.out.println(simpleDateFormat.format(date));
    }
}

常用类不常用,但是学习这些东西的时候,要学习思想,假如给你一个你没有见过的类,

你要从几点考虑:

1.这个类是干嘛?比如String处理字符串 Date处理日期时间 System是和系统有关的。专门的类做这一类相关的事儿

2.看这个类的构造方法,能不能new?

3.这个类下面java估计猜测应该封装了好多方法。要学习常用的方法

2.线程和进程【重点】

面试必问!!!

3.1什么是进程

独立运行的应用程序叫进程

什么是应用程序,就是咱们打开各个软件,比如 谷歌浏览器,360,qq音乐等这些软件,他们都是独立的一个运行起来的软件,叫应用应用程序,

代码里面写过Demo1 Demo2这些类,也可以叫一个应用程序,也可以叫进程

进程需要通过系统的分配,获取系统中的cpu,内存,显卡,网络等。

独立性 :qq和谷歌浏览器没有关系的,他们之间是独立的

互斥性:咱们软件的运行都是在抢占cpu,谁抢过谁先执行。

直到为什么有的时候一个软件会卡,让你等待。是因为这个软件在抢占cpu

的时候,没有抢占过别的软件。所以要么关闭软件,等待响应。

3.2什么是线程

进程是由多个线程组成的,而且一个进程至少得有一个线程

线程是进程的灵魂所在,看不见摸不着的。进程可以看到,在执行的这个应用程序

,但是内存是怎么运行的呢,其实是线程在运行的

线程是组成进程的最小单位。

一个人比作一个进程,那么细胞就是线程

线程具有什么特性:

1.抢占式运行

cpu执行应用程序的时候按照时间片执行的,而且单位的时间片线程是相互抢占式的运行。

厕所就三个坑位,但是学校学生300个,抢占这个坑位。谁抢到以后就先用,等你释放以后,其他人再抢。线程 很累,不断在抢占cpu,不断的释放。

2.资源共享性

一个线程可以共享当前资源,CPU 内存。

qq这个进程,比如我占用的运行内存3MB,多个线程可以共同去抢占这3MB的运行内存。

进程之间能资源共享?线程之间能资源共享吗?

进程之间不能资源共享 idea 和qq这是两个进程,可以共享资源?不可以

线程之间可以的,在一个应用程序中,抢占的同一个资源

至少有几个线程?

2个线程一个是main主函数线程,另外一个JVM垃圾回收线程。

3.3进程和线程区别【面试题】

进程是一个完整的应用程序,而且一个进程至少有一个线程,可以把进程看做一个生产车间。线程是进程中一个执行的功能,可以看成一个生产车间的一条生产线。

一个生产车间是由多个生产线组成的。一个应用程序是由多个线程组成的。

进程申请是windows系统的资源

线程申请的是进程的资源

多个线程在执行的时候,cpu会根据每个线程的分配时间片来随机轮流执行。

每个线程最多占用的时间片大概是20ms,过了这个时间片就切换到另外一线程了。

厕所比作一个应用程序,一个进程。

在这个进程中,有300个(学生)线程。去申请这个厕所的资源有3MB(3个坑位)。

每个学生抢占这个坑位,只给你留的时间片大概20ms。保证这个进程一致在执行,

没有挂掉,视觉是感应不到的他在抢占,你感觉咱们应用程序是一直在执行的。

3.4并发和并行

并发:同时发生,轮流交替来执行的。

并行:真正意义上的同时执行

举个例子:

比如你点了两盘菜,最终你都要将这两盘菜吃完,。

从老板的角度有来看。属于同时吃完的。但是严格意义上来讲,轮流交替吃的。属于并发。

并行:比如你和你同桌两个人,一人点了一个菜,你吃你的我吃我的,并行

3.5线程的优缺点

优点:

1.提高资源的利用率,cpu不至于闲着

2.电脑可以执行多个功能

3.提升用户的体验

劣势:

1.加重cpu的负担

2.降低CPU执行其他线程的概率,会导致咱们的软件的卡顿

3.共享资源的问题【重点!!!】

4.死锁的情况【避免】

3.6创建线程的两种方式

Thread

方式1: 不用!!!

1.自定义线程类去继承Thread类。重写run方法

2.在主函数中创建实例,调用start()方法开启线程

class Thread1 extends Thread{
    @Override
    public void run() {
        System.out.println("我是Thread1线程");
    }
}
public class MyThread {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();
        thread1.start();
        System.out.println("我是main主线程");
    }
}

方式2:【一般开发中使用】

1.自定义一个线程类,去实现Runnable接口,重写run方法

2.实例化线程类,这实例化好的类对象会当成一个参数传给 Thread这个类

class MThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我是MThread线程 编号:"+i);
        }
    }
}
class MThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("人家是MThread1线程啦 编号:"+i);
        }
    }
}

public class Thread2 {
    public static void main(String[] args) {
        Thread thread = new Thread(new MThread());
        thread.start();
        Thread thread1 = new Thread(new MThread1());
        thread1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("我是main主线程 编号:"+i);
        }
    }
}

        同时也可以看到线程是抢占式来获取资源的,MThread线程执行到31号就变成MThread1线程执行了

3.7线程类常用的方法

构造方法:

Thread();

创建了一个线程对象

Thread(Rnnable target);

创建线程对象,传入的的是Runnable接口的实现类

Thread(Rnnable target, String name);

创建线程对象,传入的的是Runnable接口的实现类,并给当前线程起一个名字

成员方法:

static Thread currentThread();

获取当前线程对象的

void setName(String name);

设置线程的名字

String getName();

获取线程的名字

void setPriority(int newPriority);

设置当前线程的优先级,优先级只能增加线程的执行概率,不一定的优先

线程默认的优先级是5,取值范围是1~10,10s是最高的,1的优先级最低 优先级只是调高了线程的概率,并不是按照优先级执行的,线程还是抢占式运行的

int getPriority();

获取当前线程的优先级

static void sleep();让当前线程进行休眠的,休眠的传入的是一个毫秒数

class MyThread2 implements Runnable{
    @Override
    public void run() {
        Thread thread = Thread.currentThread();//获取当前线程对象
        thread.setName("张三");//给当前线程赋名
        System.out.println(thread.getPriority());//获取当前线程优先级 默认值为5
        thread.setPriority(8);//设置线程的优先级
        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(100);//设置线程休眠时间 注意在run方法内使用sleep方法不能进行抛出异常 只能Try-catch
                System.out.println(thread.getName()+i);//thread.getName 获取当前线程的名字
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new MyThread2());
        thread.start();
        for (int i = 0; i < 50; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

3.8 关于sleep方法异常问题

class MyThread1 implements Runnable {
​
    @Override
    public void run()  {
        // TODO Auto-generated method stub
        //以下的这个代码只有一个try-catch,没有throws
        /**
         * 是因为重写,开启了严格模式,
         * 重写要求子类和父类的方法必须保持一致
         * 在Runnable接口中,run方法后面没有throws没有抛,
         * 所以子类也不能抛
         * 
         * 在以后的开发中会遇到这种情况,得想通,为啥不能抛,只能try-catch
         * 
         * */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
}
public class Demo2 {
    public static void main(String[] args) {
        
    }
​
}

3.9 同步代码块【难】

用来处理线程共享资源问题的。
共享机器:ATM机器,一个人在办理业务的时候,你进去锁门,锁住这个资源,其他人需要排队

厕所,三个坑位,我占着一个坑位,之后,后面得排队。如果不排队的话,
好几个人都抢到这个资源了,意味着一个坑位有好几个人在用!!!乱套了!!!!
就是线程不安全的情况!!!

看电影需要买电影票:
    《扫黑风暴》 【共享资源】
    网络:淘票票   美团   猫眼

    这里有三种订票方式。需要卖出去100张,通过三个渠道去卖这100张票,
    100张票就是这三个渠道的共享资源,如果把三个渠道比作三个线程,这三个线程要去共享100张票。
        卖票  ticket = 100
            淘票票 第 99
            美团  第99
            猫眼 第99
            线程的不安全性!!!

            加锁!!!线程的同步
            问题1:
                这100张票该怎么保存,选择什么数据类型?
                int 类型的数据
                成员变量?创建三个线程,如果ticket是一个成员变量的话,
                每一个销售线程ticket变量,ticket这个变量他就不是共享资源了。

                局部变量?定义在方法体内,定义在run方法中,每一次运行run方法,ticket都要重新定义一次,运行之后又销毁了,没有可持续性。
                类变量?静态变量?可以
                静态的成员变量,保存在数据区。可以提供给当前类对象使用,而且一处修改,处处修改!!!

class MovieTicket implements Runnable{
    private static int ticketNum = 100;
    @Override
    public void run() {
            while (true) {
                synchronized ("锁") {
                if (ticketNum > 0) {
                    System.out.println(Thread.currentThread().getName() + ticketNum);
                    ticketNum--;
                } else {
                    System.out.println("卖完了!");
                    break;
                }
            }
        }
    }
}

public  class Demo1 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MovieTicket(),"美团");
        Thread thread2 = new Thread(new MovieTicket(),"猫眼");
        Thread thread3 = new Thread(new MovieTicket(),"淘票票");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}



不加锁的时候会出现卖同一张电影票的情况,会导致线程不安全。

加锁的话这种情况就可以得到解决,因为加过锁之后锁内的代码块只有一个线程在执行,执行完再下一个执行,所以就不会出现卖同一张票的情况啦

 

不加锁,会导致资源不同步,线程不安全性。

加完锁以后,会解决线程不安全的问题。但是你的执行效率比不加锁的时候低

追求安全,不要追求效率了

卖火车票一样。

下去可以看看这个博客,多学点!!!

Java 多线程详解(三)------线程的同步 - YSOcean - 博客园

理解至上,代码可以不会写,但是线程怎么走的必须得知道

3.10 守护线程

例如:

qq,内网通这些聊天软件,主程序叫非守护线程。而所有的聊天窗口线程叫守护线程。

如果主程序关闭,聊天窗口也就会关闭了。

主线程挂了,那么守护线程也随即挂了。

jvm,垃圾回收线程就是守护线程。当一个应用程序执行完毕,gc这个线程就停止了

守护线程就好比一个小喽喽,他的生死无关紧要,依赖整个主线程而运行的。但是起到的作用很大。

好比古代,皇帝死了以后,会有陪葬的。这个陪葬的就是守护线程

以后开发中,软件更新。日志更新,都是需要用到守护线程的。

3.11 死锁

面试的时候会问!!!开发的时候千万别写死锁!!!

死锁是一种bug的存在

1.什么是死锁

2.死锁有什么危害

3.代码实现一个必然的死锁。

3.11 什么是死锁

关键词:并发场景,多线程, 互不相让

死锁一定发生在并发场景,尤其是锁,目的是为了线程安全,物极必反。

死锁是一种状态,当两个线程互相持有对方的资源的时候,却又不主动释放自己手中的资源,导致大家都用不了了。线程无法继续往下执行。被称为死锁!!!

写出一个死锁【java代码】

class DeadLocking implements Runnable {
    private boolean flag;
    private Object object1;
    private Object object2;

    public DeadLocking(boolean flag, Object object1, Object object2) {
        this.flag = flag;
        this.object1 = object1;
        this.object2 = object2;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (object1) {
                System.out.println("我是" + Thread.currentThread().getName() + "获得的锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我准备获得Thread-1的锁");
                synchronized (object2) {
                    System.out.println(Thread.currentThread().getName() + "获得了全部锁");
                }
            }
        }
        if (!flag) {
            synchronized (object2) {
                System.out.println("我是" + Thread.currentThread().getName() + "获得的锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我准备获得Thread-0的锁");
                synchronized (object1) {
                    System.out.println(Thread.currentThread().getName() + "获得了全部锁");
                }
            }
        }
    }
}

public class Demo3 {
    public static void main(String[] args) {
        Object object1 = new Object();
        Object object2 = new Object();
        DeadLocking deadLocking1 = new DeadLocking(true, object1, object2);
        DeadLocking deadLocking2 = new DeadLocking(false, object1, object2);
        Thread thread1 = new Thread(deadLocking1);
        Thread thread2 = new Thread(deadLocking2);
        thread1.start();
        thread2.start();
    }
}

​可以看到程序一直在运行,没有停止

以上的代码看看就行了,千万不要模仿着去写,开发中这种情况是禁止的,不能写死锁

线程1锁lock1 但是想申请lock2。这个时候线程2已经获得了lock2这个锁对象了,在释放lock2之前得获取lock1对象,形成了一个闭环,陷入死锁循环

找了开锁公司,给你卡一个箱子。但是开锁需要证明身份。但是你证明身份的东西在箱子里面。 开锁公司:你先证明你的身份

你:证明身份东西在箱子里面,你打开之后我就能证明

开锁公司:有规定,你必须先证明你身份。

死锁!!!

3.12 线程的生命周期

1.创建线程

2.线程开启

3.可运行状态

4.运行状态

5.中间有可能阻塞 sleep() 死锁 只要你线程执行不下去,都算阻塞了。

6.线程的销毁

声明周期,就好比一个人的人生。

人先生出来,(人吃奶长大,上学,不挣钱)可运行状态,(工作 挣钱)运行状态

(失业了挣不了钱了)阻塞 ,人挂了。这个人的一生

3.13 线程的三个重要的方法

是Object下面的方法

wait()

调用该方法的线程处于等待状态【阻塞状态】,需要使用对象调用这个方法

而且这个对象必须是锁对象,wait方法一般和锁一起使用

notify()

唤醒线程,需要通过对象来调用,而且这个对象是锁对象

唤醒一个线程

notifyAll()

唤醒多个线程

Message类

public class Message {
    private String message;//声明一个类,然后这个类实例化以后,当成一个锁对象看待

    public Message(){}

    public Message(String message){
        this.message=message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Waitter类 和 Waitter2类

import java.text.SimpleDateFormat;

public class Waitter implements Runnable{//一个线程,这个线程有阻塞,需要使用noitify来唤醒的线程
    private Message message;

    public Waitter(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (message){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
            System.out.println(name+" 获得锁的时间是:"+simpleDateFormat.format(System.currentTimeMillis()));
            System.out.println("=====================");
            try {
                message.wait();//线程走到这个地方,突然阻塞了,这个线程,突然暂停。
				//这个wait方法 是需要另外一个线程来唤醒他,唤醒他以后,再继续执行下面的代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name+"起床啦!!!"+message.getMessage());
    }
}
import java.text.SimpleDateFormat;

public class Waitter2 implements Runnable{
    private Message message;

    public Waitter2(Message message) {
        this.message = message;
    }


    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (message){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
            System.out.println(name+" 获得锁的时间为:"+simpleDateFormat.format(System.currentTimeMillis()));
            System.out.println("=====================");
            try {
                message.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name+"起床啦!!!"+message.getMessage());
    }
}

Notify类

public class Notify implements Runnable{
    private Message message;

    public Notify(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        try {
            Thread.sleep(10000);//让线程2休眠10s 目的为了等待线程1进入等待状态
            synchronized (message){
                //message.notify();
                //唤醒了另外一个线程,唤醒的是随机的
                message.notifyAll();
                //message.notifyAll();方法是把所有wait的线程都唤醒
                System.out.println(name+" 直接唤醒一波!");
                System.out.println("====================");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Client类

public class Client {
    public static void main(String[] args) {
        Message message = new Message("我是你爹");
        Waitter waitter = new Waitter(message);
        Waitter2 waitter2 = new Waitter2(message);
        Notify notify = new Notify(message);
        Thread thread1 = new Thread(waitter,"线程1");
        Thread thread2 = new Thread(waitter2,"线程2");
        Thread thread3 = new Thread(notify,"线程3");
        thread1.start();
        thread2.start();
        System.out.println("====================");
        thread3.start();
        /**
		 * 
		 * 好比:
		 * 	你是一个等待线程:写的有wait方法
		 * 		本来在上线下课,疫情了,会发生阻塞,接到政府通知,不能出门
		 * 政府是一个唤醒线程:写了notify方法
		 * 		说疫情结束了,小区解封,给你一个通知,我才能出门
		 * 
		 * 总结:最起码的两个线程:一个等待线程  wait()
		 * 						另外一个肯定是唤醒线程  notify()		
		 * 		这两个方法必须一起使用,不然你写的代码毫无意义,代码不执行了
		 * 
		 * */
    }
}


大家也可以看浏览一下这篇博客详细了解锁

Java中Synchronized的用法(简单介绍) - 韦邦杠 - 博客园

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波波奶茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值