多线程、高并发、线程安全
synchronized同步方法
摘要:
1、方法内部的私有变量不存在线程安全问题;
2、多线程中用不同的对象调用同一个对象锁同步方法(非静态),是异步执行的;
3、
类锁跟对象锁是两把锁,一线程A类型a对象调用对象锁同步方法M1,二线程A类调用类锁同步(静态同步)方法M2,
结果:M1跟M2的执行顺序是异步的,因为
这是两把锁(不会出现锁占用),执行方法M1时用的是对象锁,
执行方法M2时(不管是用
其他对象去调用还是
直接用类名调用)用的是类锁,所以执行顺序是异步的。
如果都调用M2,不管是几个不同对象(或者用类名)那么就都
用的类锁,这样的话将是同步执行的;
4、synchronized修饰的
非静态方法、synchronized修饰
(this){代码块} 针对的都是对象锁,一个对象一把锁,不同对象不同锁,
如:一线程A类型a1对象调用对象锁同步方法M1,二线程A类型对象a2(跟a1不是一个实体)也调用对象锁同步方法M1,
结果:两个M1的执行顺序是异步的,因为两个对象两个对象锁;
5、synchronized修饰的
静态方法、synchronized修饰
(A.class){代码块} 针对的都是类锁,类锁只有一把,全局共享一把类锁,
多线程中不管是用任何对象调用这个类锁方法,还是用类名直接调用,多线程中这个方法执行的顺序都是同步的;
6、对象锁同步方法M1,对象锁同步方法M2,一线程中用A类型对象a调用M1,二线程中也用A类型对象a(同一个实例),调用
方法M2,结果:
两个方法执行的顺序是同步的,因为是锁占有(同一个对象同一个锁);
7、类锁同步方法M1,类锁同步方法M2,一线程中(用不管任何A类型对象、类名)调用M1,二线程中调用方法M2,
结果:两个方法执行的顺序是同步的,因为锁占有(占用着同一把类锁);
8、类锁同步方法M1,对象锁同步方法M2,一线程中调用M1(不管是对象调用还是类调用),二线程中调用M2(不管是不是同一个实例对象),
结果:M2、M1都是异步执行,两个线程中掉用的是
不同的锁方法,不会出现锁占用(第3点已经说明);
package base.thread;
public class A {
public static synchronized void M2() {
for(int i=0;i<100;i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("M2:"+i);
}
}
public synchronized void M1() {
for(int i=0;i<100;i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("M1:"+i);
}
}
}
package base.thread;
public class TwoKindsOfLockMain {
public static void main(String[] args) {
A a = new A();
new Thread(() -> {
a.M1();
}).start();
new Thread(() -> {
A.M2();
}) .start();
}
}
M1:0
M2:0
M1:1
M2:1
M1:2
M2:2
...
内存可见性
volatile修饰词
package base.thread;
/**
* @author G_Y
* 2018年3月12日
* 说明:内存可见性经典测试
* 线程工作区如果不跟主内存进行交互 则 数据不能进行 同步
* 调用静态、native方法也能跟主内存交互
*/
public class MainThreadTest {
private static boolean b = Boolean.FALSE;//volatile 修饰就能及时知道数据的值
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
int i = 0;
while (!b) {
i++;
/*try {
Thread.sleep(100);//调用native方法也能跟主内存交互
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
//System.out.println(1);//调用同步方法也能跟主内存交互 当前线程内存跟主内存同步
}
System.out.println("thread over");
}).start();
Thread.sleep(1000);
b = Boolean.TRUE;
System.out.println("main over");
}
}
线程死锁
用类锁举例:
如:线程1中占用着类型A的类锁等待着类型B的类锁释放,线程2中占用着类型B的类锁等待着类型A的类锁释放,
然后其他线程都
没机会使用类A的
所以类锁
方法,也
不能使用类B的所以
类锁
方法;
也可用对象锁举例: