一、线程简介
请看:https://blog.csdn.net/qq_33157666/article/details/103949005
二、线程状态
请看:https://blog.csdn.net/qq_33157666/article/details/103949045
三、线程同步
为什么要进行线程同步?
java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如对其进行增删改查操作),会导致数据不准确,而且相互之间产生冲突。所以加入同步锁以避免该线程在没有完成操作前被其他线程调用,从而保证该变量的唯一性和准确性。
3.1初识并发问题
//多个线程同时操作同一个对象
//买火车票的例子
//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据混乱
public class TestTheard4 implements Runnable{
//票数
private int ticketNumbers=10;
@Override
public void run() {
while(true){
if(ticketNumbers<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"--->拿到了"+ticketNumbers--+"票");
}
}
public static void main(String[] args) {
TestTheard4 testTheard4=new TestTheard4();
new Thread(testTheard4,"小明").start();
new Thread(testTheard4,"小张").start();
new Thread(testTheard4,"黄牛党").start();
}
}
可以看到小明和小张同时拿到了第9张票,这样线程是不安全的,需要做到同步,可以把同步理解成排队,不让多个线程操作同一个对象。可使用synchronized关键字实现同步。
引起线程不安全的原因:
每个线程的内存都是独立的,当两个线程同时访问一个对象时,会把对象复制到自己内存中,所以,如果想线程安全需要排队。
3.2 同步方法
同步方法:用synchronize关键字修饰的方法,当用synchronize关键字修饰方法时,一个线程持有锁后将其他需要此锁的线程挂起。
代码修改:将4.1代码的run方法改为:
@Override
public synchronized void run() {
3.3同步代码块
同步代码块:就是拥有synchronize关键字修饰的语句块
代码修改:将4.1代码的
@Override
public void run() {
while(true){
synchronized (this) {
if(ticketNumbers<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"--->拿到了第"+ticketNumbers--+"票");
}
}
}
3.4小结
synchrionized实现同步的原理:
synchronized方法控制对象访问,每个对象对应一个把锁,每个synchized方法必须获得调用对象该对象的锁才能执行,否则会线程阻塞,方法一旦执行,就独占改锁,知道该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,持续执行。
使用synchronized的缺点:
- 一个线程持有所会导致其他需要此锁的线程挂起,在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
- 如果有一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。
四、死锁
请看:https://blog.csdn.net/qq_33157666/article/details/103949174