博客园的第一天--2022.01.01元旦

近两个月学习总结

自学部分:面向对象、集合框架、IO流、异常处理、泛型

培训一个月零7天:从线程开始、网络编程、单例,枚举,工厂模式、反射,注解、Lambda表达式,StreamAPI、mysql数据库、JDBC、HTML、CSS、JavaScript

线程

一.进程和线程:

1.1进程是操作系统调度的最小单位,进程独立占用CPU和内存资源。

1.2线程是CPU调度调度的最小单位,一个进程中某个功能就可以对应一个线程。

1.3线程隶属于进程,多个线程之间共用进程的资源(CPU和内存之间)。

二.CPU时间片:

CPU在一个时间点只能为一个线程服务,但是CPU时间片可以非常快速的在多个线程之间切换,逻辑感觉多个线程是同时运行的。多个线程抢CPU时间片,谁抢到谁执行!所以并发只是逻辑感觉,单核CPU是无真正并发,多核CPU可以真并发。

三.创建线程:

3.1自定义一个类extends Thread,并重写Thread的run();

或者自定义一个类 implements Runnable接口;

 

或者JDK1.5 以后又有通过实现callable接口

 3.2创建线程对象:

或者

3.3启动线程:

3.4总结:

建议使用第二种方式创建线程:

    1.实现了线程对象和要执行操作之间的解耦

    2.可以实现多继承:一个类可以实现多个接口

    3.使用第二种方法仍然可以再继承别的类。

四.设置线程优先级

线程对象.setPriority(整数);

注意:整数[1,10]

Thread.MAX_PRIORITY:10

Thread.NORM_PRIORITY:5

Thread.MIN_PRIORITY:1

开发中建议使用Thread的静态常量设置线程的优先级。

五.守护线程:

    5.1随着主线程的结束而结束,主线程存活期其一直存活。

    5.2设置一个线程为守护线程: 线程对象.setDaemon(true);

    5.3GC就是一个守护线程:

    Garbage Collection:GC

    GC是Java中的内存回收线程:

    I.长时间未使用的对象会被GC回收

    II.没有引用指向的对象会被GC很快回收

    System.gc():通知GC尽快回收未使用的对象,不是立即回收。

   JVM退出之前,GC一直存在。

六.如何让线程进入阻塞状态:

6.1阻塞态:

    1.使正在运行的线程失去CPU时间片,在阻塞期间被剥夺了CPU时间片的抢夺权;

    2.阻塞结束后回到Runnable状态,加入CPU时间片的抢夺;

6.2Thread.sleep(毫秒数):让当前正在运行的线程进入阻塞态多少毫秒。

    正常情况下,睡眠时间结束,进入Runnable,但如果线程在阻塞期间,睡眠被打断(线程对象.interrupt()),会提前进入Runnable

6.3join():一个线程可以使用join()剥夺另外一个线程的CPU时间片,强行加入执行

6.4Scanner的输入方法会阻塞所有线程。

七.线程的同步和异步

7.1线程的异步:

线程默认是异步,你执行你的,我执行我的,多个线程之间执行互不干涉:谁抢到CPU时间片谁执行;多个线程执行步调不一致

7.2线程的同步:

一个线程的执行会影响到另一个线程:如果一个线程未执行完,其他线程会进入阻塞状态,等待其执行完毕

特征:线程执行有先后顺序。

同步:指的是一个线程的状态受另外一个线程影响;未抢到锁的线程等待抢到锁的线程释放锁。

7.3使线程进入同步状态的方式:

    1.join():被join的线程和join线程步调一致;Join的线程执行完,被join的再执行。

    2.使用同步锁synchronized):

7.4何时使用:

   如果多个线程有临界资源(共同访问的资源),可能发生线程并发(同时访问)问题,此时建议使用同步锁。

7.5使用过后:

   线程由异步变成同步

   I.抢到锁的线程有权限去争夺CPU时间片

   II.未抢到锁的线程进入锁池(相当于阻塞态)

   III.未抢到锁的线程等待抢到锁的线程释放锁(锁代码块执行完毕)才能去抢锁

7.6对谁加锁:

多个线程有临界资源,对临界资源加锁,锁的范围要尽可能小(加锁和释放锁比较耗时):只要能够解决并发问题即可:哪里用到了临界就锁哪里。(也可以锁Runnable对象或者方法)

7.7死锁概念:

    线程甲拥有A资源,需要访问B资源;

    线程乙拥有B资源,需要访问A资源;

    产生的无限互相等待对方释放锁的过程就是死锁。

7.8产生原因:

    嵌套锁,并且对多个临界资源加锁的顺序不一致:

7.9如何避免:

    1.尽量不编写锁嵌套

    2.如果有锁嵌套,要保证对临界资源加锁顺序一致。

7.10何时使用线程同步:

   1.提高某个线程的优先级(在一个时间段内独占CPU):比如医院叫号插队

   2.对临界资源一定要进行同步,否则可能产生线程并发问题。

八.wait()和notify()

8.1wait()和notify()成对使用:

1.都必须在锁代码块中使用

2.wait():立即释放锁,进入阻塞状态,直到接收到notify通知,进入锁池开始抢锁

3.notify():获得锁的线程执行完毕后通知释放锁的线程,可以抢锁了。

8.2注意:

wait和notify()不是线程类的方法,是Object类的方法:

wait和notify()使用需要通过临界资源.wait()/临界资源.notify()

九.线程生命周期

9.1NEW:新建态

线程对象被创建出来,但未开始运行:已经new出但未start();

9.2RUNNABLE:可运行

线程对象.start()之后进入RUNNABL;此时线程具有抢夺CPU时间片的权利;并且只有处于RUNNABLE状态的线程才具有抢夺CPU时间片的资格

9.3BLOCKED:阻塞态

被阻塞的线程不再具有抢夺CPU时间片的权利;

未抢到锁的线程就进入阻塞状态:锁池中的线程

9.4WAITING:WAITING阻塞态

wait():释放锁,进入等待队列,也是被阻塞,等待被notify(唤醒)

Join():也是进入阻塞态,等待被加入的线程执行完毕。

9.5TIMED_WAITING:带时间限制的阻塞态

Thread.sleep(毫秒数):阻塞毫秒数结束后自动进入RUNNABLE状态

join(毫秒数):阻塞毫秒数结束后自动进入RUNNABLE状态

wait(毫秒数):阻塞毫秒数结束后自动进入锁池:具有资格抢锁。

9.6TERMINATED:死亡态

线程的run()或者主线程的main()执行完毕:正常死亡;

程序运行遇到异常:非正常死亡

注意:

1.被阻塞的线程不再具有抢夺CPU时间片的权利

2.锁池中的线程(未获得锁的线程)不能直接进入RUNNABLE,需要先抢锁再抢CPU时间片。

3.等待队列的线程不能直接进入锁池:需要被notify(唤醒)或者阻塞时间到

十.线程安全和非线程安全

线程安全:不会产生线程并发问题。

线程非安全:有可能产生线程并发问题。

常用的集合框架API一般都是线程非安全的:
ArrayList HashSet HashMap都是线程非安全,无临界资源无需加锁。

但Java中也提供了一些线程安全的集合:

Vector:线程安全的ArrayList,Vector的方法是线程安全的。

实际开发中一般使用线程非安全的集合框架:代码执行效率高,如果遇到线程并发问题,自定义同步锁,Vector等线程安全的集合框架只是方法安全,但不能保证我们代码是线程安全的。

HashTable和HashMap的区别(了解)

  1. HashTable是线程安全的,HashMap是线程非安全的。
  2. HashTable的key和value都不允许为null
  3. HashMapkey和value都允许为null.

StringBuffer是线程安全的,StringBuilder是线程非安全的。

 

 

 

posted @ 2022-01-02 20:58  java菜鸟周小天  阅读(36)  评论(0)    收藏  举报