Java多线程和高并发

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

什么是进程、线程?

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

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

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

线程的状态

synchronized关键字

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

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

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

public synchronized void m() { 
	count--;
	System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public void m() {
	synchronized(this) { //任何线程要执行下面的代码,必须先拿到this的锁
		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,所以在线程执行时间很长,或者线程很多时,使用重量级锁更合适。在线程执行时间短,线程数较少时,可以使用自旋锁来提高效率。

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注