多线程基础概念

1、进程与线程
操作系统划分的功能单元,拥有自己的私有虚拟空间。线程是包含在进程中的执行单元。
线程的状态:新建状态,就绪状态(执行了start方法),运行状态,阻塞状态(执行wait方法等待阻塞,获取同步锁,sleep,join,IO请求),死亡状态(执行完毕或者异常退出run方法)。
2、java线程栈与java实例
java线程工作时是从主内存中拷贝的变量副本,当线程操作完这个变量时再写回主内存,线程是不能直接使用主内存变量的。当多线程共享一个实例的时候,就会出现线程安全的问题,要保证java实例的原子性和可见性,就要使用锁的机制。

3、生产者与消费者问题,哲学家进餐问题。
面向作业流的,在生产者和消费者之间建立缓冲区作为管道消息交互,异步处理业务。
实现方法一:利用Object的wait()和notify()方法
不满足条件object.wait()等待,执行完之后object.notifyAll()通知其他线程
实现方法二:await() signal()方法 比wait notify具有更大的灵活性,通过在Lock对象上调用newCondition()方法将条件变量和锁对象绑定控制并发访问。
// 锁
final Lock lock = new ReentrantLock()
// 条件变量1
final Condition cond1 = lock.newCondition();
// 条件变量2
final COndition cond2 = lock.newCondition();

// 生产方法
product(){
// 获取锁
lock.lock();
// if条件不满足
cond1.await();
// if条件满足
XXX 业务代码
// 执行完成
cond1.signalAll();
cond2.signalAll();
// 释放锁
lock.unlock();
}

// 消费方法
consume(){
// 原理同上,条件换成cond2
cond2.await()
}

方法三:BlockingQueue阻塞队列,队列内部实现了同步,实现方式就是方法二
put()方法,生产者线程,当容量满时,自动阻塞
take()方法,消费者线程,容量为0时,自动阻塞


4、线程安全
线程锁,synchronize ReentrantLock volatitle
java线程安全的目的是要控制多个线程对某个资源的有序访问和修改。这个涉及java内存模型和java的同步机制。
主内存和线程工作内存的关系:当我们new一个对象的时候是在主内存中的,线程保存的是对象的副本,线程之间是不能直接通信的,主内存是多个线程共享的,
当线程要操作某个对象的时候顺序是这样的:
(1)从主内存复制变量到线程工作内存read and load
(2)执行代码,改变值。use and assign
(3)用工作内存数据刷新主内存
那么,什么是有序性呢 ?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本 (use),也就是说 read,load,use顺序可以由JVM实现系统决定。
        线程不能直接为主存中中字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store- write),至于何时同步过去,根据JVM实现系统决定.有该字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线程会引用该变量副本,当同一线程多次重复对字段赋值时,比如:
Java代码  
  1. for(int i=0;i<10;i++)   
  2.  a++;  
 for(int i=0;i<10;i++)
  a++;
 

线程有可能只对工作内存中的副本进行赋值,只到最后一次赋值后才同步到主存储区,所以assign,store,weite顺序可以由JVM实现系统决定。假设有一个共享变量x,线程a执行x=x+1。从上面的描述中可以知道x=x+1并不是一个原子操作,它的执行过程如下:
1 从主存中读取变量x副本到工作内存
2 给x加1
3 将x加1后的值写回主 存
如果另外一个线程b执行x=x-1,执行过程如下:
1 从主存中读取变量x副本到工作内存
2 给x减1
3 将x减1后的值写回主存 
那么显然,最终的x的值是不可靠的。假设x现在为10,线程a加1,线程b减1,从表面上看,似乎最终x还是为10,但是多线程情况下会有这种情况发生:
1:线程a从主存读取x副本到工作内存,工作内存中x值为10
2:线程b从主存读取x副本到工作内存,工作内存中x值为10
3:线程a将工作内存中x加1,工作内存中x值为11
4:线程a将x提交主存中,主存中x为11
5:线程b将工作内存中x值减1,工作内存中x值为9
6:线程b将x提交到中主存中,主存中x为9 
同样,x有可能为11,如果x是一个银行账户,线程a存款,线程b扣款,显然这样是有严重问题的,要解决这个问题,必须保证线程a和线程b是有序执行的,并且每个线程执行的加1或减1是一个原子操作。
synchronized(锁){   
临界区代码   
}  
一个线程执行临界区代码过程如下:
1 获得同步锁
2 清空工作内存
3 从主存拷贝变量副本到工作内存
4 对这些变量计算
5 将变量从工作内存写回到主存
6 释放锁
可见,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。

5、四种线程池
// newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
// newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
// newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
// newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
6、java并发包详细介绍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程和线程是操作系统中的两个基本概念,它们都是用来执行程序的执行单元,但在一些方面有着明显的区别。 1. 进程(Process): - 进程是程序在执行过程中的一个实例。 - 每个进程都有自己的独立内存空间,包括代码段、数据段和堆栈段。 - 进程之间相互独立,拥有各自的资源,通信需要通过进程间通信(IPC)机制。 - 进程拥有自己的进程控制块(PCB),用于描述进程的状态、资源和调度信息。 2. 线程(Thread): - 线程是进程中的一个执行单元。 - 多个线程可以共享同一个进程的内存空间,包括代码段、数据段和堆栈段。 - 线程之间共享进程的资源,如打开的文件、信号处理等。 - 线程线程控制块(TCB)来描述,每个线程有自己的栈和寄存器上下文。 区别: 1. 资源占用:每个进程都有独立的内存空间和系统资源,而线程共享进程的资源。 2. 创建销毁开销:创建或销毁进程比线程开销大,因为进程需要分配独立的内存空间和系统资源,而线程只需要创建线程控制块。 3. 切换开销:进程切换的开销较大,需要保存和恢复整个进程的上下文,而线程切换只需要保存和恢复线程的上下文。 4. 通信和同步:进程间通信需要使用进程间通信机制,如管道、消息队列等。线程间通信和同步相对容易,可以使用共享内存、信号量、互斥量等机制。 总结: 进程和线程都是用于执行程序的执行单元,但进程是资源分配的基本单位,线程是CPU调度的基本单位。多线程比多进程更轻量级,线程之间的切换开销更小,但进程之间相互独立,安全性更高。在实际应用中,需要根据具体需求选择使用进程还是线程

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值