Java多线程和高并发

说到并发,就要提到一个最基本的概念,线程和进程。

什么是进程、线程?

当一个程序运行时,会产生一个进程,一个进程中最小的一个执行单元,为一个线程。当一个程序刚启动时。

在Java如果创建一个线程呢?

有两种方法,一是从Thread继承,二是实现Runnable。通过线程池来创建的线程也是这前两种方式实现的。

线程的状态

Image for post

synchronized关键字

synchronized关键字的作用是给某个对象加锁,目的是在多个线程同时操作时保证其状态正确。只有线程获取到锁的时候,才可以对目标对象进行操作。这个关键字既可以保证原子性,也可以保证可见性。

synchronize在Hotspot中实现是通过对象头中的两位,即Mark code来判断是否获取到锁。

synchronized修饰方法,和synchronize(this)效果是相同的,比如如下两段代码:

public synchronized void m() { 
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}

synchronized是可重入锁,即同一个线程内,如果两个方法都是同一把锁,那么获取到线程获取到锁后,这两个方法都可以执行。比如如下代码,m1中可以正常调用m2:

synchronized void m1() {
System.out.println("m1 start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
m2();
System.out.println("m1 end");
}

synchronized void m2() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2");
}

如果在程序中出现异常,那么默认情况下锁将被释放。

synchronized的底层实现

早期JDK的synchronized实现是重量级的系统锁,效率很低。

后期进行了改进,在第一个对象获取锁的时候,在锁的对象头中记录了这个线程的id(偏向锁),当第二个线程来获取锁时,锁升级为自旋锁,当自旋10次后,再升级为重量级锁。这大大提高了效率。但是锁只能升级,不能降级。

但是自旋锁会占用CPU,所以在线程执行时间很长,或者线程很多时,使用重量级锁更合适。在线程执行时间短,线程数较少时,可以使用自旋锁来提高效率。

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store