Java 进程与线程的对比
- 进程是资源分配的最小单位,线程是程序执行的最小单位,是系统独立调度和分派 CPU 的基本单位
- 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此 CPU 切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多,线程的上下文切换的性能消耗要小于进程。
- 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行
我们所说的锁其实是对象锁,对于static修饰的方法,锁定的是该类所有的对象,也就是说共享一个锁,而对于非static方法,则一个对象一把锁
两个对象二把锁
public class MultiThread {
private int num = 200;
public synchronized void printNum(String threadName) {
num = num - 100;
System.out.println(threadName + " num="+num);
}
public static void main(String[] args) throws InterruptedException {
final MultiThread multiThread1 = new MultiThread();
final MultiThread multiThread2 = new MultiThread();
new Thread(new Runnable() {
public void run() {
multiThread1.printNum("thread1");
}
}).start();
new Thread(new Runnable() {
public void run() {
multiThread2.printNum("thread2");
}
}).start();
}
}
//static修饰的方法后
public class MultiThread {
static private int num = 200;
static public synchronized void printNum(String threadName) {
num = num - 100;
System.out.println(threadName + " num="+num);
}
public static void main(String[] args) throws InterruptedException {
final MultiThread multiThread1 = new MultiThread();
final MultiThread multiThread2 = new MultiThread();
new Thread(new Runnable() {
public void run() {
multiThread1.printNum("thread1");
}
}).start();
new Thread(new Runnable() {
public void run() {
multiThread2.printNum("thread2");
}
}).start();
}
}
可重入锁
-
关键字 Synchronized 拥有锁重入的功能,也就是在使用 Synchronized 的时候,当一个线程得到一个对象的锁后,在该锁里执行代码的时候可以再次请求该对象的锁时可以再次得到该对象的锁。
-
也就是说,当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。
-
可重入锁的目的就是避免自己调用自己的同步方法时,出现死锁现象
volatile变量 与 synchronize的区别
- 关键字 volatile 是线程同步的轻量级实现,性能比 synchronized 要好,并且 volatile 只能修于变量,而 synchronized 可以修饰方法,代码块等。
- 多线程访问 volatile 不会发生阻塞,而 synchronized 会发生阻塞。
- 可以保证数据的可见性,但不可以保证原子性,而 synchronized 可以保证原子性,也可以间接保证可见性,因为他会将私有内存和公共内存中的数据做同步。
- volatile 光靠可加性,并不能实现线程安全,而synchronize可以实现线程安全
wait()方法 和 notify()方法对比
-
wait() 和 notify() 方法要在同步块或同步方法中调用,即在调用前,线程也必须获得该对象的对象级别锁。
-
wait 方法是立即释放锁, notify 方法之后,当前线程不会立即释放其拥有的该对象锁,而是notify()所在方法执行完之后才会释放该对象锁,被通知的线程也不会立即获得对象锁,而是等待notify()所在方法执行完之后,释放了该对象锁,才可以获得该对象锁。
-
notify 每次唤醒 wait 等待状态的线程都是随机的,且每次只唤醒一个。
-
notifAll 每次唤醒 wait 等待状态的线程使之重新竞争获取对象锁,优先级最高的那个线程会最先执行。
-
当线程处于 wait() 状态时,调用线程对象的 interrupt() 方法会出现 InterruptedException 异常。