浅析线程及同步



守护线程
通常情况下 后台的应用程序就是守护程序 被守护的线程结束了即使守护的线程没有结束那么也将会结束


线程的局部变量:解决多线程共享同个对象的时候,对象属性数据安全问题
ThreadLocal通过get获取


线程池:线程的容器可以帮助我们进行线程的创建。ExecutorService


说明:线程类,创建线程的主要类
Thread currentThread() 获取当前代码所在的线程对象
String getName() 获取线程的名称
主线程名:main
子线程名:Thread-编号,编号从0开始
void setName(String?name) 设置线程的名称
long  getId() 获取线程的id
boolean isAlive() 是否处于活动状态
Thread.State getState()  返回该线程状态
Thread.State.NEW 创建状态
Thread.State.RUNNABLE 就绪状态-可运行状态
Thread.State.TERMINATED 结束状态
Thread.State.BLOCKED 阻塞状态
Thread.State.TIMED_WAITING 休眠状态
Thread.State.WAITING 等待状态
阻塞状态
主线程名:main
子线程名:Thread-编号,编号从0开始
Thread.State.NEW 创建状态
Thread.State.RUNNABLE 就绪状态-可运行状态
Thread.State.TERMINATED 结束状态
Thread.State.BLOCKED 阻塞状态
Thread.State.TIMED_WAITING 休眠状态
Thread.State.WAITING 等待状态
void setDaemon(boolean?on) 将该线程标记为守护(后台)线程或用户线程
Thread.sleep(long millis) 将线程转入等待状态(TIMED_WATING)
Thread.yield() 线程让步,把执行机会让给相同或者更高优先级的线程,但随后仍然可能继续执行
void join() 线程加入,当前线程进入WAITING状态,当被调用的线程运行结束,则当前线程再转为Runnable状态
void setPriority(int newPriority) 设置优先级
int getPriority() 获取优先级
Runnable接口
说明:线程体接口,只拥有线程执行的任务,不具有线程功能
作用:为相同程序代码的多个线程提供共享的数据
public void run() 抽象方法
说明:线程体接口,只拥有线程执行的任务,不具有线程功能
作用:为相同程序代码的多个线程提供共享的数据
public void run() 抽象方法


1、一个进程中的每个线程都在栈中有一块自己的内存
多线程与栈
1、一个进程中的每个线程都在栈中有一块自己的内存
2、只有当线程执行完自己的任务代码时,才会释放自己所占的内存
3、只有当进程中的所有线程结束了,该进程才结束
2、只有当线程执行完自己的任务代码时,才会释放自己所占的内存
3、只有当进程中的所有线程结束了,该进程才结束


线程加锁


使用notify的时候一定要注意使用的是while 要不会出现错误


synchronized 采用的是悲观锁
lock 乐观锁 。


synchronized(对象){}
使用之后就会释放锁
使用lock接口对锁进行了单独的描述


创建一个lock的子类reentrantlock
使用lock替代我们的同步代码块
需要同步的代码放入lock和unlock、之间


condition 使用的是await() signal() signalAll()




说明:用于解决线程间共享数据时存在的安全问题
互斥锁
作用:在Java中引入对象互斥锁的概念,保证共享数据操作的完整性
说明:每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象
关键字:synchronized,用来给对象加互斥锁
解决方式
当一个线程得到cpu,执行操作共享数据的多条语句时,其它线程不能参与执行,只有该线程把所有操作共享数据的语句全部执行完,其它线程才能参与执行
自由主题
当一个线程得到cpu,执行操作共享数据的多条语句时,其它线程不能参与执行,只有该线程把所有操作共享数据的语句全部执行完,其它线程才能参与执行
线程同步
说明:用于解决线程间共享数据时存在的安全问题
互斥锁
作用:在Java中引入对象互斥锁的概念,保证共享数据操作的完整性
说明:每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象
关键字:synchronized,用来给对象加互斥锁
三种加锁方式
1、同步非静态方法
格式:public synchronized void method1(){}
说明:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象
如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后
2、同步static方法
格式:public synchronized static void method1()
说明: synchronized放在static方法声明中,表示锁定该类的class对象
如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响
3、同步代码块
同步this:
    synchronized(this){//this被加锁,任何其他要锁this的代码块被阻塞.
      需要同步的代码;
  }
同步obj:
synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.
    需要同步的代码;
}
说明:synchronized放在对象前面限制一段代码的执行
线程同步的弊端
不能进入同步代码块的线程会反复的判读锁,降低了程序的性能
使用同步需要满足的条件
1、同步中至少有两个线程
2、使用同一把锁
避免死锁
由于线程1锁住资源A等待资源B,线程2锁住资源B等待资源A,两个线程都在等待自己需要的资源,而这些资源被另外的线程锁住,这些线程你等我,我等你,谁也不愿意让出资源,这样死锁就产生了
三种加锁方式
1、同步非静态方法
格式:public synchronized void method1(){}
说明:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象
如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后
2、同步static方法
格式:public synchronized static void method1()
说明: synchronized放在static方法声明中,表示锁定该类的class对象
如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响
3、同步代码块
同步this:
    synchronized(this){//this被加锁,任何其他要锁this的代码块被阻塞.
      需要同步的代码;
  }
同步obj:
synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.
    需要同步的代码;
}
说明:synchronized放在对象前面限制一段代码的执行
线程同步的弊端
不能进入同步代码块的线程会反复的判读锁,降低了程序的性能
使用同步需要满足的条件
1、同步中至少有两个线程
2、使用同一把锁
避免死锁
由于线程1锁住资源A等待资源B,线程2锁住资源B等待资源A,两个线程都在等待自己需要的资源,而这些资源被另外的线程锁住,这些线程你等我,我等你,谁也不愿意让出资源,这样死锁就产生了


线程之间的通信:


说明:多个线程执行的任务不同,但是操作的资源是相同的
生产者消费者模式
生产者(Producer)与消费者(Consumer)的问题
生产者将产品交给店员(Clerk),而消费者从店员处取走产品,店员一次只能持有固定数量的产品,如果生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
生产者(Producer)与消费者(Consumer)的问题
生产者将产品交给店员(Clerk),而消费者从店员处取走产品,店员一次只能持有固定数量的产品,如果生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
理解等待与唤醒

Object类中的wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll() 唤醒方法
线程等待
Object类中的wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll() 唤醒方法
Object 类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。
线程唤醒
Object 类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。
Object类中的notifyAll()方法,唤醒在此对象监视器上等待的所有线程。
Object类中的notifyAll()方法,唤醒在此对象监视器上等待的所有线程。
注意:wait()、notify()和notifyAll()三个方法只能在被同步化(synchronized)的方法或代码块中调用


线程的停止:


1、如果线程的run()方法中执行的是一个重复执行的循环,可以提供一个“标记”来控制循环是否继续执行
2、对于正在执行的线程,interrupt()无法打断该线程的执行,但是可以获得该线程被中断的标志: Thread.interrupted()得到true,调用后,中断标志将被清除(变为false)
3、如果线程因为执行join(),sleep()或是wait()而进入了阻塞状态,此时要想停止它,可以使用interrupt(),程序会抛出InterruptException异常而被catch()子句捕获,进行处理
4、如果程序因为输入/输出的等待而阻塞,基本上必须等待输入/输出的动作完成才能离开阻塞状态。无法用interrupt()方法来使得线程离开run()方法,要想离开,只能通过引发一个异常。


对于锁的操作:
jdk1.5之前对锁的操作是隐式的
synchronized(对象)//获取锁
{
   需要同步的代码
}//释放锁
jdk1.5使用Lock接口对锁进行的单独的描述---面向对象
自由主题
Lock接口
说明:JDK1.5提供的同步锁操作接口
Condition newCondition() 获取锁的情况,便于操作线程的状态或条件
lock() 获取锁
unlock() 释放锁
synchronized(对象)//获取锁
{
   需要同步的代码
}//释放锁
涉及核心接口与类
Lock接口
说明:JDK1.5提供的同步锁操作接口
Condition newCondition() 获取锁的情况,便于操作线程的状态或条件
lock() 获取锁
unlock() 释放锁
ReentrantLock类
接口Lock的实现类
int getHoldCount()
int  getQueueLength()
int getWaitQueueLength(Condition condition)
boolean hasQueuedThreads() 判断锁的等待池中是否存在多个线程
boolean hasWaiters(Condition c) 判断锁的等待池中包含condition条件的线程
Conditon接口
说明:提供锁所在线程的状态操作,如等待与唤醒
await() 等待
signal() 唤醒
signalAll() 唤醒所有
ReentrantLock类
接口Lock的实现类
int getHoldCount()
int  getQueueLength()
int getWaitQueueLength(Condition condition)
boolean hasQueuedThreads() 判断锁的等待池中是否存在多个线程
boolean hasWaiters(Condition c) 判断锁的等待池中包含condition条件的线程
Conditon接口
说明:提供锁所在线程的状态操作,如等待与唤醒
await() 等待
signal() 唤醒
signalAll() 唤醒所有
1、创建Lock的子类对象
2、调用Lock对象的newCondition()创建线程状态控制对象
3、把需要同步的代码放在lock()和unlock()之间
使用步骤
1、创建Lock的子类对象
2、调用Lock对象的newCondition()创建线程状态控制对象
3、把需要同步的代码放在lock()和unlock()之间
4、在用到wait()、notify()等地方,改换成Condition对象的相关方法
注意
1、多个线程之间只能存在一个Lock对象
2、为了避免死锁,一般将解锁位置放在finally语句中
3、对于wait-notify状态转换应该产生两个Condition对象进行控制
4、在用到wait()、notify()等地方,改换成Condition对象的相关方法
注意
1、多个线程之间只能存在一个Lock对象
2、为了避免死锁,一般将解锁位置放在finally语句中
3、对于wait-notify状态转换应该产生两个Condition对象进行控制


线程的局部变量:


涉及的类:java.lang.ThreadLocal 
作用:用于解决多个线程共享同一个对象时,对象属性的数据安全问题.
1) 每一个ThreadLocal对象就像一个整个楼的信箱,每一个线程只能打开其中的一个属于自己的信箱.这个信箱只能放一个对象.
说明
1) 每一个ThreadLocal对象就像一个整个楼的信箱,每一个线程只能打开其中的一个属于自己的信箱.这个信箱只能放一个对象.
2)本质上ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本.且无需知道key是什么(其实是当前线程).也不会错用到其他线程的局部变量.
2)本质上ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本.且无需知道key是什么(其实是当前线程).也不会错用到其他线程的局部变量.




后台守护线程:


说明:在后台运行的线程,为其他的线程提供服务
设置方法:setDaemon(boolean b) 把一个线程设置成后台线程
1、经常用于任务结束时的善后处理,典型的后台线程是定时器Timer线程
作用
1、经常用于任务结束时的善后处理,典型的后台线程是定时器Timer线程
2、后台线程的优先级比其他线程的低
3、如果没有“用户线程”在运行,JVM将退出,守护线程将被自动终止
2、后台线程的优先级比其他线程的低
3、如果没有“用户线程”在运行,JVM将退出,守护线程将被自动终止




多线程编程一般规则
1、如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。
2、不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的
3、如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。
4、每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。
5、记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。




多线程编程一般规则:


1、如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。
2、不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的
3、如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。
4、每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。
5、记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。


static void sleep (Long毫秒)制定的毫秒之内使运行的线程睡眠
 会抛出异常 Throws InterruptedException() 线程休眠是帮助所有线程获得资源的最好的方法
 线程睡眠之后自动苏醒,返回到就绪状态不是运行状态
  sleep指定的时间是休眠之后可运行的最短的时间不能保证到期之后就开始运行
  是静态的方法智能控制当前的线程


线程的优先级,级别越高机会越多,级别越低机会越少不绝对
最大是10 最小是1 默认是5
使用setPriority()
getPriority()


线程的join()方法线程的合并 当前线程等待该线程执行完毕
static yield(0当前线程让步只会让步一次下一次是哪个线程是不一定了
线程的中断的方法
interrupt()线程的中断的方法更改了中断的标志false--》true
static boolean interrupted() 是否被中断的状态 返回的就是flag 但是有一个查除的方法




实现的原理是什么就是锁定一个对象


实现同步的方式:同步代码块 synchronized(锁){}方法代码执行完成后自动解锁,可以使任意的对象Object obj = new Object
synchronized()
this 锁住当前的对象把当前的对象声明成一个锁
可以锁住一个字符串
运行时的锁
静态的数据调用的时候使用的是运行时的锁
同步的方法 在方法的前面加上synchronized
同步静态方法锁定的是this对象
同步静态方法锁定的是XXX.class




多线程需要同步机制


数据安全 :
采用同步代码块的方式 synchronized(){}
类型可以是任意的对象
当前的对象this 同时可以是静态的对象
还有一种采用同步方法注意方法的粒度


多线程共享数据的时候多条,一个线程执行操作共享数据如果还没执行完成,就被其他的线程抢占到CPU那么这个过程中就会出现数据不安全一个得到CPU那么其他的CPU就只能等待直到该线程执行完成为止。
使用同步代码块的好处就是:将共享数据放到里面,但是降低了性能需要不断的访问看看是不是锁已经被释放。


使用同步时候满足条件:
至少两个线程
使用同一把锁









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值