博客园的第一天--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的区别(了解)
- HashTable是线程安全的,HashMap是线程非安全的。
- HashTable的key和value都不允许为null
- HashMap的key和value都允许为null.
StringBuffer是线程安全的,StringBuilder是线程非安全的。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号