1、volatile与synchronized原子性区别
不用volatile修饰变量不用synchronized修饰方法
package com.example.demo.gc13;
public class T extends Thread {
// volatile和synchronized
int count = 0;
@Override
public void run(){
for(int i =0;i<100;i++){
count++;
System.out.println(Thread.currentThread().getName()+"-"+count);
}
}
public static void main(String[] args) {
T t = new T();
Thread thread1 = new Thread(t,"t1");
Thread thread2 = new Thread(t,"t2");
thread1.start();
thread2.start();
}
}
出现线程不安全问题
只用volatile也只能保证线程可见性。不能保证原子性
package com.example.demo.gc13;
public class T extends Thread {
// volatile和synchronized
volatile int count = 0;
@Override
public void run(){
for(int i =0;i<100;i++){
count++;
System.out.println(Thread.currentThread().getName()+"-"+count);
}
}
public static void main(String[] args) {
T t = new T();
Thread thread1 = new Thread(t,"t1");
Thread thread2 = new Thread(t,"t2");
thread1.start();
thread2.start();
}
}
volatile联合synchronized解决变量可视性和原子性问题
package com.example.demo.gc13;
public class T extends Thread {
// volatile和synchronized
volatile int count = 0;
@Override
public synchronized void run(){
for(int i =0;i<100;i++){
count++;
System.out.println(Thread.currentThread().getName()+"-"+count);
}
}
public static void main(String[] args) {
T t = new T();
Thread thread1 = new Thread(t,"t1");
Thread thread2 = new Thread(t,"t2");
thread1.start();
thread2.start();
}
}
2、synchronized优化
####对于重量级锁。在保证线程安全的前提下。能效率尽量效率。能锁变量锁变量。能锁对象锁对象。能锁方法锁方法。最后不行锁类
package com.example.demo.gc16;
import java.util.concurrent.TimeUnit;
/**
* synchronized优化
* 同步代码块中语句越少越好
* 比较m1和m2
*/
public class FineCoarseLock extends Thread{
static int count = 0;
synchronized void m1(){
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
// 其实在业务逻辑中只需要这里加锁,不需要整个方法加锁影响性能
for (int i=0;i<50;i++){
count++;
System.out.println(Thread.currentThread().getName()+"-"+count);
}
try{
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
}
void m2(){
try{
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
// 细粒度锁。只需锁定当前变量
synchronized (this){
for (int i=0;i<50;i++){
count++;
System.out.println(Thread.currentThread().getName()+"-"+count);
}
}
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
// 测试两个方法结果是否一样
FineCoarseLock lock = new FineCoarseLock();
/* Runnable r = new Runnable() {
@Override
public void run() {
lock.m1();
}
};
// 启动线程
new Thread(r,"t1").start();
new Thread(r,"t2").start();*/
Runnable r2 = new Runnable() {
@Override
public void run() {
lock.m2();
}
};
new Thread(r2,"t1").start();
new Thread(r2,"t2").start();
}
}
两个方法的结果一样的。但明显m2效率会提升
3、synchronized对象锁
package com.example.demo.gc17;
import java.util.concurrent.TimeUnit;
public class T {
// synchronized对象锁
/*final*/ Object o =new Object();
void m(){
synchronized (o){
while (true){
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
T t = new T();
new Thread(t::m,"t1").start();
try{
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
// 创建第二个线程
Thread t2 = new Thread(t::m,"t2");
// 改变锁对象。t2线程得以执行。如果没有以下代码。则线程2无法执行
t.o = new Object();
t2.start();
}
}
t1、t2交替执行
我们使用对象锁的时候。就是为了避免。对象发生改变。变成别的对象。导致数据有问题,在加锁的对象前加final最终引用
package com.example.demo.gc17;
import java.util.concurrent.TimeUnit;
public class T {
// synchronized对象锁
final Object o =new Object();
void m(){
synchronized (o){
while (true){
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
T t = new T();
new Thread(t::m,"t1").start();
try{
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
// 创建第二个线程
Thread t2 = new Thread(t::m,"t2");
// 改变锁对象。t2线程得以执行。如果没有以下代码。则线程2无法执行
// t.o = new Object();
t2.start();
}
}
t2根本就没有执行的机会,达到此行目的
####synchronized锁的是对象而不是代码
锁方法时候锁的是this
锁static方法锁的是class
锁定方法和非锁定方法是可以同时执行的
锁升级从偏向锁到自旋锁到重量级锁
####volatile保证线程可见性,同时防止指令重排序。线程可见性在cpu级别是用缓存保证。禁止指令重排序是cpu级别。禁止不了的提升效率的。在虚拟机级别加volatile之后可以指令重排序禁止。其实这里就是给cpu加读写屏障。