场景-> 需求 -> 解决方案-> 应用-> 原理
总结一下自己对synchronized的理解 如有疏漏不妥之处,还请不吝赐教;
1.多线程有哪些的优点
我们都知道 线程的合理使用能够提升程序的性能, 其主要原因有以下两方面
- 能够利用多核cpu以及超线程技术来实现线程的并行执行
- 线程的异步化执行相比于同步化执行,异步化执行能够很好的优化程序处理提升性能并发吞吐量
2.什么是多线程对于共享变量访问带来的安全性问题?
public class Demo {
private static int count = 0;
public static void inc() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
public static void main(String[] args) throws InterruptedException {
for(int i = 0; i <1000 ; i++){
new Thread(()-> Demo.inc()).start();
System.out.println("创建的第"+i+"个线程");
}
Thread.sleep(3000);
System.out.println("运行结果" + count);
}
}
想一下这段代码运行结果输出的是多少?
正确的结果为1000 ,因为出现了线程安全问题 所以 运行结果只有988
- 一个对象是否是线程安全 ,取决于他是否会被多个线程访问,以及程序中是如何使用这个对象的。所以,如果多个线程访问同一个共享对象,在不需要额外的同步以及调用端代码不用做其他协调的情况下 这个共享对象的状态依然正确(正确意味着这个对象的结果与我们的预期规定的结果保持一致),说明这个对象是线程安全的
3.如何保证线程并行的数据安全?
- java提供了synchronized 关键字
4.synchronized 的基本认识
synchronized 简述: java se 1.6 之前synchronized 一直是以重量锁的身份存在 ,但在java se 1.6 为了减少获得锁和释放锁带来的性能消耗而引入了 偏向锁和轻量锁 ,synchronized 变得也不那么重了
synchronized的三种加锁方式 :
1 修饰实例方法 作用于当前实例加锁 , 进入同步代码块前要获得当前实例的锁
private static Object lock;
public static void inc() {
synchronized(lock){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
2 静态方法 , 作用于当前类对象加锁 ,进入同步代码块前要获得当前类对象的锁
public synchronized static void inc() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
3 修饰代码块 指定加锁对象 ,对给定对象加锁, 进入同步代码块前 要获得给定对象的锁
public void inc() {
synchronized(this){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
//等同于
public synchronized void inc() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
这样就可以解决共享数据的线程安全问题