java并发编程总结一(待补充)

synchronized关键字

对某个对象进行加锁
使用synchronized关键字有以下三种使用方式:

  1. 同步代码块
    同步代码块锁的是括号里面的配置对象
  2. 同步方法
    同步方法锁的是当前实例对象
  3. 静态同步方法
    静态同步方法锁的是当前类的Class对象
  • 自己新建一个对象作为锁住的对象
public class T{
	private int count = 10;
	private Object o =new Object();
	public void m(){
		synchronized(o){
			count--;
			System.out.println(Thtread.currentThread().getName() + "count = " + count);
		}
	}
}
  • 使用this对象作为锁对象

public class T{
	private int count = 10;
	public void m(){
		synchronized(this){//同步代码块
			count--;
			System.out.println(Thtread.currentThread().getName() + "count = " + count);
		}
	}
}
  • 上文代码的另外一种写法
public class T{
	private int count = 10;
	public synchronized void m(){//同步方法
		count--;
		System.out.println(Thtread.currentThread().getName() + "count = " + count);
	}
}
  • 静态同步方法:没有this对象的静态方法如何获得锁对象
public class T{
	private int count = 10;
	public synchronized void m(){
		count--;
		System.out.println(Thtread.currentThread().getName() + "count = " + count);
	}
	public static void mm(){
		synchronized(T.class){//静态的方法没有this对象,所以用反射来获取它的锁对象
			count--;
		}
	}
}
public class T implements Runnable{
	private int count = 10;
	public /*synchronized*/ void run(){//synchronized所标注的代码块具备原子性,执行期间不可再分
		count--;
		System.out.println(Thtread.currentThread().getName() + "count = " + count);
	}
	public void main(){
		T t = new T();//只有一个对象
		for(int i = 0; i < 5; i++){
			new Thread(t, "THREAD" + i).start();//开启五个线程,共同访问t对象,共同访问count
		}
	}
}

同步方法和非同步方法是否可以同时被调用

在一个同步方法执行的过程中,非同步的方法可以运行,因为非同步方法的执行不需要锁

public class demo6 {
	public synchronized void m1() {
		System.out.println(Thread.currentThread().getName() + "m1 start.... ");
		try {
			Thread.sleep(10000);
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "m1 end.... ");
		
	}
	
	public void m2() {
		try {
			Thread.sleep(5000);
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "m2 .... ");
	}
	
	public static void main(String[] args) {
		demo6 t = new demo6();
		
		new Thread(()->t.m1(), "t1").start();
		new Thread(()->t.m2(), "t2").start();

	}
}	

脏读

写时需要加锁,读时其实也需要加锁,否则容易出现脏读的现象

/*写的时候加锁
 * 读的时候不加锁
 * 脏读的现象
 */
package concurrent1;
import java.util.concurrent.TimeUnit;
public class demo8 {
	String name;
	double balance;
	
	public synchronized void set(String name, double balance) {
		this.name = name;
		
		try {
			Thread.sleep(2000);
		}catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		this.balance = balance;
	}
	
	public double getBalance(String name) {
		return this.balance;
	}
	
	public static void main(String[] args) {
		demo8 aDemo8 = new demo8();
		
		new Thread(()->aDemo8.set("zhangsan", 100.0)).start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		}catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		System.out.println(aDemo8.getBalance("zhangsan"));
		
		try {
			TimeUnit.SECONDS.sleep(2);
		}catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		System.out.println(aDemo8.getBalance("zhangsan"));
	}
}

可重入
import java.util.concurrent.TimeUnit;

/*
 * 一个同步方法是否可以调用另外一个同步的方法
 * 一个已经拥有某个对象锁的线程,再次申请的时候仍然会得到该对象的锁
 * 即:synchronized获得的锁是可以重入的
 */
public class demo9 {
	synchronized void m1() {
		System.out.println("m1 start...");
		try {
			TimeUnit.SECONDS.sleep(1);
		}catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		m2();
	}
	
	synchronized void m2() {
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		System.out.println("m2");
	}
}

  • 子类中调用父类的同步方法
//子类中调用父类的同步方法
import java.util.concurrent.TimeUnit;

public class demo10 {
	synchronized void m() {
		System.out.println("m start  ..");
		try {
			TimeUnit.SECONDS.sleep(1);
		}catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		System.out.println("m end");
	}
	
	public static void main(String[] args) {
		new TT().m();
	}
}

class TT extends demo10{
	@Override
	synchronized void m() {
		System.out.println("child m start");
		super.m();
		System.out.println("child m end");
	}
}
程序在执行过程中出现异常,锁会被释放
import java.sql.Time;
import java.util.concurrent.TimeUnit;

/*
 * 程序在执行时,如果出现异常,默认情况下锁会被释放,这时其他的线程访问的数据可能会出现不一致的情况
 */
public class T {
	int count = 0;
	synchronized void m() {
		System.out.println(Thread.currentThread().getName() + "  start ");
		while(true) {
			count++;
			System.out.println(Thread.currentThread().getName() + "count = " + count);
			try {
				TimeUnit.SECONDS.sleep(1);
			}catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			
			if(count == 5) {
				int i = 1/0;
			}
		}
	}
	
	public static void main(String[] args) {
		T t =new T();
		
		Runnable r = new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				t.m();
			}
		};
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();			
		}
		new Thread(r, "t2").start();
	}
}
volatile 关键字:内存可见性

使一个变量在多个线程间可见。

Java编程语言允许线程访问共享变量,为了确保共享变量能够准确一致地更新,线程确保通过排他锁单独获得这个变量。

Java中的volatile关键字就是这个定义的体现。如果一个变量被声明为volatile,那么确保这个变量是“可见的”。可见性的意思是当线程修改一个共享变量的时候,另外一个线程能够读到这个修改的值。

具体原理参见:这个

例子:

public class T {
	volatile boolean running = true;
	void m() {
		System.out.println(" m start ");
		while(running) {
			
		}
		System.out.println("m end ...");
	}
	
	public static void main(String[] args) {
		T t =new T();
		
		new Thread(t::m, "t1").start();
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();			
		}
		t.running = false;
	}
}
volatile 与synchronized的区别:

volatile只能保证可见性
synchronized既保证可见性又保证了原子性

public class T {
	volatile int count = 0;//只保证可见性
	void m() {
		for(int i = 0; i < 10000; i++) count++;
	}
	
	public static void main(String[] args) {
		T t =new T();
		
		List<Thread> threads = new ArrayList<Thread>();
		
		for(int i = 0; i < 10; i++)
			threads.add(new Thread(t::m, "thread-" + i));
		
		threads.forEach((o)->o.start());
		
		threads.forEach((o)->{
			try {
				o.join();
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		});
		
		System.out.println(t.count);
	}
}
使用Atomic***类来保证原子性
public class T {
	AtomicInteger count = new AtomicInteger(0);
	void m() {
		for(int i = 0; i < 10000; i++){
//			if(count.get() < 1000)  //使用Atomicxxx的多个方法并不具备原子性
			count.incrementAndGet();//用于替代count++的
		}
	}
	
	public static void main(String[] args) {
		T t = new T();
		
		List<Thread> threads = new ArrayList<Thread>();
		
		for (int i = 0; i < 10; i++) {
			threads.add(new Thread(t::m, "thread-" + i));
		}
		
		threads.forEach((o) -> o.start());
		
		threads.forEach((o) -> {
			try {
				o.join();
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		});
		System.out.println(t.count);
	}
	
}
synchronized的优化
public class T {
	int count = 0;
	synchronized void m1() {
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		count++;
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	void m2() {
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		//业务逻辑中只有下面的这句话需要同步,这时不应该在给整个方法加上锁
		//采用更加细粒度的方法,可以使线程争用的时间变短,提高效率
		synchronized (this) {
			count++;
		}
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}	
}
锁住的对象属性发生改变不会影响锁的使用,但是如果引用的对象改变情况就大为不同了
public class T {
	Object o = new Object();
	
	void m() {
		synchronized (o) {
			while(true) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (Exception e) {
					// TODO: handle exception
					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(3);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		Thread t2 = new Thread(t::m, "t2");
		
		t.o = new Object();
		
		t2.start();
	}
}
不应该用字符串作为锁定的对象
public class T {

	String s1 = "Hello";
	String s2 = "Hello";
	
	void m1() {
		synchronized (s1) {
			
		}
	}
	
	void m2() {
		synchronized (s2) {
			
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值