多线程笔记

多线程出现的原因:
为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等,比如:读写文件,视频图像的采集,处理,显示,保存等

使用多线程好处:
1,提高效率(尽可能的充分利用系统资源cpu)
多线程的缺点:
1,如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.
2,更多的线程需要更多的内存空间

创建线程的方法:
(1)Thread:new一个Thread的子类,Thread就是java中的线程。

   class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
    }
}

(2)Runnable:创建一个接口,new一个Runnable接口的子类,传到Thread中执行,Runnable是java中任务的概念,new一个Runnable,就是定义一个任务的描述,再传入Thread线程中执行

(3)Callable:创建一个接口,strat()方法来启动线程,真正实现了多线程的运行,run()方法作为普通方法的调用

线程
运行一个java程序(系统分配的java进程的内存空间),会启动main线程执行main主函数。
内存(栈,堆,方法区)

  1. 栈:(线程私有)包含局部变量表(局部变量+基础数据类型)
  2. 堆:(线程共享)对象和数组(虽然是共享,但是线程能不能用,取决于线程是否能获利到对象的引用)
  3. 方法区:(线程共享)方法区与java堆一样,是各个线程共享的内存区域,它用于储存已被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据

线程不安全的原因:
(1)从代码层面:
多个线程对于同一变量的操作(读,写)有一个写操作,就有线程安全问题
(2)从原理上看:
1,原子性
多行代码执行时,是一组不可再分的最小单位。是指再进行一系列操作的时候这些操作要么全部执行,要么全部不执行。

关于原子性,我们把一串代码想象成一个房间,每个线程就是要进入这个房间的人,如果没有任何安全机制,那么A进入这个房间之后,还没有出来,B是不是也可以这个房间,打断A的隐私,这个就是不具备原子性的。我们只需要在这个房间上一把锁,A进去后把锁锁上,就保证了原子性

2,可见性
为了提高效率,JVM在执行时会尽可能的将数据在工作内存中执行,但这样会造成一个问题,共享变量在多线程之间不能及时看到改变,这个就是可见性问题。

关于可见性 ,主存:线程都使用的共享区域,对其对象的操作。工作内存:线程之间互相不可见

3,有序性
java代码顺序是固定的,但是JVM执行字节码或cpu执行机器码,都有可能重排序,对其进行优化,带来的问题单线程情况下没有问题,但是在多线程下就有问题

如何解决多线程的不安全问题?
一组代码,如果存在多线程对共享变量的操作都需要考虑线程安全问题synchronized关键字:依次执行某段代码
使用:
1,在静态方法上:加锁整个方法,锁对象为当前的类对象
2,在实例方法上:加锁整个方法,锁对象为this(哪个对象调用this就指向谁)
3,同步代码块:synchrinized(锁对象)
作用:对同一个对象加锁的过程,造成同步互斥作用(多个线程依次执行临界区代码),本质上是对象头进行加锁,对同一个对象加锁的线程,是同步互斥的
线程池:
1,作用:不用每次执行任务时,都创建线程(会真实创建系统级别的线程,比较耗时,销毁也是),而是可是使用线程池中的线程来复用。
2,Thread Pool Executor 每个参数的意义

Thread Pool Executor pool =new ThreadPoolExecutor(
4,//线程核心数,快递公司的正式员工数
10,//最大线程数,快递公司的总员工=正式员工+临时工
60,//空闲时间数,
TimeUnit,SECONDS,//时间单位
new ArrayBlockingQueue<>(1000),
new ThreadFactory(){
@Override
public Thread newThread(Runnable r){ //线程的工厂类:快递公司招聘标准
return new Thread(r);
}
},
new ThreadPoolExecutor。DiscardPolicy()//不处理新包裹,直接丢掉
);
corePoolSize:核心线程数,线程定义了可以同时运行大的线程量
maximumPoolSize:线程池中允许存在的工作线程的最大数量
workQueue:存放任务的容器,当新任务来了会判断当前运行的线程数量是否达到核心线程数,如果达到,任务就先放到队列中

3,线程池执行的顺序

4,快捷方法创建的4种线程池,为什莫工作中不能用?
默认创建的方式,没有指定线程创建的工厂类,及指定拒绝策略,如果提交任务的速度比执行任务速度块,阻塞队列中的任务会越来越积攒,如果超过java进程的内存,就会出现DOM内存溢出,整个进程挂掉

数据库中的乐观锁和悲观锁是什么?怎么实现?适用于
那些场景?

  • 悲观锁:悲观的以为总是会发生并发冲突,屏蔽一切可能违反数据完整性的操 作。在查询完数据的时候就把事务锁起来,直到提交事务。
  • 实现方式:使用数据库中的锁机制。
  • 乐观锁:乐观的以为不会发生并发冲突,等到提交的时候检查是否违反了数据 库完整性。在修改数据的时候把事务锁起来。
  • 实现方式:一般采用版本号机制

或者CAS实现。
使用场景:
乐观锁适用于多读场景,即冲突真的很少发生的场景;
悲观锁适用于多写场景,因为多写的情况下,一般会经常发生冲突;

CAS
CAS——CompareAndSwap——比较并交换
CAS包含三个操作数——内存位置(V)、预期值(A)、拟写入的新值(B)
第一步:比较内存位置V中的值和预期值A是否相等
第二步:如果相等,就把拟写入的新值B写入内存位置V
第三步:返回boolean类型值,表示操作是否成功
当多个线程同时对某个资源进行CAS操作的时候,只能有一个线程操作成功,其他线
程会自旋等待。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值