java并发编程学习(一)

1.wait()和notify()

public class MyThread {

	public static List<String> list = new ArrayList<String>();
	public static void main(String[] args) {
		Thread thread = new Thread(){
			@Override
			public void run() {
				synchronized (MyThread.class) {
					if(list.size() == 0){
						try {
							MyThread.class.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					list.remove(0);
					System.out.println("消费了一个");
				}
			}
		};
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		thread.start();
		list.add("aaa");
		System.out.println("生产了一个");
		synchronized (MyThread.class) {
			MyThread.class.notify();
		}
	}
}

wait和notify方法都必须在synchronized代码块中执行,

源码中有以下注释

     * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code notify} method for a
     * description of the ways in which a thread can become the owner of
     * a monitor.

synchronized代码块通过javap生成的字节码中包含 monitorenter 和 monitorexit 指令。而wait()和notify()方法执行时都需要拿到当前对象的监视器。

运行以上代码得到如下

如果去掉synchronized则会报错

另外补充很重要的一点,jdk在wait()方法注释中不推荐使用if推荐使用while来进行判断

     * As in the one argument version, interrupts and spurious wakeups are
     * possible, and this method should always be used in a loop:
     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait();
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>

因为线程在等待时可能由于伪唤醒而进入运行状态。伪唤醒是指由于操作系统、cpu调度的原因等不是由java代码进行的唤醒操作。

因此代码作如下改动:

public class MyThread {

	public static List<String> list = new ArrayList<String>();
	public static void main(String[] args) {
		Thread thread = new Thread(){
			@Override
			public void run() {
				synchronized (MyThread.class) {
					while(list.size() == 0){
						try {
							MyThread.class.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					list.remove(0);
					System.out.println("消费了一个");
				}
			}
		};
		thread.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		list.add("aaa");
		System.out.println("生产了一个");
		synchronized (MyThread.class) {
			MyThread.class.notify();
		}
	}
}

wait()和sleep()区别

1.sleep()属于Thread类,wait()属于object类

2.sleep()会出让cpu但不会释放对象锁,wait()则会释放对象锁等待唤醒

2.LockSupport中的park() 和 unpark()

public class MyThread2 {

	public static volatile List<String> list = new ArrayList<String>();
	public static void main(String[] args) {
		Thread thread = new Thread(){
			@Override
			public void run() {
				if(list.size() == 0){
					LockSupport.park(MyThread2.class);
				}
				list.remove(0);
				System.out.println("消费了一个");
			}
		};
		thread.start();
		list.add("aaa");
		System.out.println("生产了一个");
		LockSupport.unpark(thread);
	}
}

park()、unpark()和wait()、notify()的区别

1.park、unpark不需要写在synchronized代码块中

2.先执行多次unpark后,在第一次执行执行park时会立刻接着执行

3.volatile和synchronized

一般来说,我们拿到变量都是拿到其在内存中的一个副本,修改也是对副本进行修改。在一个代码块中对其进行操作完成后才更新的内存之中。volatile修饰的变量能确保变量每次进行修改都是直接在内存上进行修改。

synchronized确保操作的原子性,就是要么全都执行要么全都不执行。但synchronized会导致指令重排序,在一个线程拿到对象的同步锁之后,其他所有线程都处于等待。释放锁之后,其他想要拿到该对象的同步锁的线程是随机一个拿到锁,并不是按时间顺序拿到锁,因此可能不是按代码顺序来执行的。而volatile禁止指令重排序,同时性能上也优于synchronized;

synchronized和volatile不能互相替代。synchronized确保可见性、原子性,不能确保有序性;volatile确保可见性、有序性,不能确保原子性。

补充:synchronized修饰方法时拿到的是对象锁

4.双重检查锁

高并发下单例的获取方法

public class InstanceFactory {
	public volatile static Instance instance;
	public Instance getInstance(){
		if(instance == null){
			synchronized (InstanceFactory.class) {
				if(instance == null){
					instance = new Instance();
				}
			}
		}
		return instance;
	}
}

高并发下缓存的获取

public class CacheDemo {
	public <T>T getSomeInfo(){
		T t = getCache();//获取缓存
		if(t == null){ 
			synchronized (CacheDemo.class) {
				t = getCache();//获取缓存
				if(t == null){
					t = getDB();//从数据库获取
                                        setCache(t);
				}
			}
		}
		return t;
	}

	private <T> T getDB() {
		// TODO Auto-generated method stub
		return null;
	}

	private <T> T getCache() {
		// TODO Auto-generated method stub
		return null;
	}
        private <T> void setCache(T t){
		// TODO Auto-generated method stub
        }
}

5.join()

join()是Thread类里的方法

调用t.join()方法会阻塞当前线程,直到线程t结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值