Java 併發(JUC 包-01)

>JUC ? 就是Java API 中這三個包的簡稱:

>atomic 包

CAS:compare and swap ?要實現原子性操作

這是一種原子性操作,這是一種原子性賦值,

比如原來的 ++i ,現在對 i 進行原子性加一,從Java5之後就有了這個原子性操作,主要藉助unsafe類(源碼無法查看),Java爲我們封裝了一些類:

在atomic 包中

之前的例子改一下:

public class TestAtomic {
	V v = new V();

	public static void main(String[] args) {
		TestAtomic ta = new TestAtomic();
		ta.go();
	}

	private void go() {
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				public void run() {
					for (int j = 0; j < 10000; j++) {
						v.add();
					}
				}
			}).start();
		}
		while (Thread.activeCount() > 1) {

		}
		System.out.println(v.ai.get());
	}

	class V {
		//public int i = 0;
          public AtomicInteger ai=new AtomicInteger();
		public void add() {//原本在這個地方加個鎖,將整個方法鎖住了,悲觀鎖(重量級鎖)
			//如果i++ 變成原子性的就沒必要在外部加鎖了
			//i++;
			ai.getAndIncrement();
		}
	}
}

>locks 包

1.重入鎖基本使用:

public class TestLock {

	public static void main(String[] args) {
		new TestLock().go();
	}

	public void go() {
		V v = new V();
		new Thread(new Runnable() {
			public void run() {
				while (true) {
					v.printString("AAAAAAAAAAAAAA");
				}
			}
		}).start();
		new Thread(new Runnable() {
			public void run() {
				while (true) {
					v.printString("BBBBBBBBBBBBBB");
				}
			}
		}).start();
	}

	class V {
		// 使用Lock 代替 synchronized
		ReentrantLock lock = new ReentrantLock();

		public void printString(String str) {
			try {
				lock.lock();
				for (int i = 0; i < str.length(); i++) {
					System.out.print(str.charAt(i));
				}
				System.out.println();
			} catch (Exception e) {
			} finally {
				// 爲了確保鎖可以被釋放掉
				lock.unlock();
			}

		}
	}
}

2.條件鎖:使用條件鎖實現線程輪詢

public class TestConditionLock {
	V v = new V();

	public static void main(String[] args) {
		TestConditionLock t = new TestConditionLock();
		t.go();
	}

	private void go() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					v.f1();
				}
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					v.f2();
				}
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					v.f3();
				}
			}
		}).start();
	}

	class V {
		Lock lock = new ReentrantLock();
		Condition condition1 = lock.newCondition();
		Condition condition2 = lock.newCondition();
		Condition condition3 = lock.newCondition();
		int token = 1;

		public void f1() {
			lock.lock();
			try {
				while (token != 1) {
					try {
						condition1.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				token = 2;
				System.out.println(Thread.currentThread().getName() + "--f1");
				condition2.signal();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}

		public void f2() {
			lock.lock();
			try {
				while (token != 2) {
					try {
						condition2.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				token = 3;
				System.out.println(Thread.currentThread().getName() + "--f2");
				condition3.signal();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}

		public void f3() {
			lock.lock();
			try {
				while (token != 3) {
					try {
						condition3.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				token = 1;
				System.out.println(Thread.currentThread().getName() + "--f3");
				condition1.signal();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}
}

3.讀寫鎖:

讀寫鎖分爲讀鎖和寫鎖。多個讀鎖之間不互斥、讀鎖和寫鎖之間互斥、寫鎖和寫鎖之間互斥。這一功能很重要,對併發讀取提高了性能。

讀寫鎖使用到了JUC中的ReentrantReadWriteLock類:

/**
 * 測試讀寫鎖: 1.有個地方存東西 2.提供讀和寫兩個方法,對這兩個地方進行操作 3.開啓多個線程,有讀,有寫 4.證明讀的時候可以讀,寫的時候不能其他操作
 */
public class TestReentrantReadWriteLock {
	public static void main(String[] args) {
		TestReentrantReadWriteLock t = new TestReentrantReadWriteLock();
		t.go();
	}

	Data d = new Data();
	Random r = new Random();

	private void go() {
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					d.write(r.nextInt(1000));
				}
			}).start();
		}
		for (int i = 0; i < 5; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					d.read(r.nextInt(999));
				}
			}).start();
		}
	}

	class Data {
		List<Integer> list = new ArrayList<>();

		{
			for (int i = 0; i < 1000; i++) {
				list.add(i);
			}
		}

		// 創建讀寫鎖
		ReadWriteLock lock = new ReentrantReadWriteLock();
		Lock readLock = lock.readLock();
		Lock writeLock = lock.writeLock();

		public void read(int index) {
			readLock.lock();
			try {
				System.out.println(Thread.currentThread().getName() + "進入讀方法");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				int i = list.get(index);
				System.out.println(Thread.currentThread().getName() + "讀到數據" + i);
				System.out.println(Thread.currentThread().getName() + "讀取完畢");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				readLock.unlock();
			}
		}

		public void write(int data) {
			writeLock.lock();
			try {
				System.out.println(Thread.currentThread().getName() + "進入寫方法");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				list.add(data);
				System.out.println(Thread.currentThread().getName() + "寫入完畢");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				writeLock.unlock();
			}
		}
	}
}

顯示:

Thread-0進入寫方法
Thread-0寫入完畢
Thread-1進入寫方法
Thread-1寫入完畢
Thread-2進入寫方法
Thread-2寫入完畢
Thread-3進入讀方法
Thread-4進入讀方法
Thread-5進入讀方法
Thread-6進入讀方法
Thread-7進入讀方法
Thread-4讀到數據403
Thread-5讀到數據276
Thread-5讀取完畢
Thread-7讀到數據98
Thread-7讀取完畢
Thread-6讀到數據628
Thread-6讀取完畢
Thread-3讀到數據258
Thread-3讀取完畢
Thread-4讀取完畢

數據庫中有表級別鎖,行級鎖,如何實現?思考。

單例模式中的同步代碼塊如何取代:

先看API實例:

class CachedData {
   Object data;
   volatile boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        try {
          // Recheck state because another thread might have
          // acquired write lock and changed state before we did.
          if (!cacheValid) {
            data = ...
            cacheValid = true;
          }
          // Downgrade by acquiring read lock before releasing write lock
          rwl.readLock().lock();
        } finally {
          rwl.writeLock().unlock(); // Unlock write, still hold read
        }
     }

     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }

改造一下單例:

public class Book {
	private static Book instance = null;
	private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

	public static Book getInstance() {
		try {
			rwl.readLock().lock();
			if (instance == null) {
				rwl.readLock().unlock();
				rwl.writeLock().lock();
				if (instance == null) {
					instance = new Book();
				}
				rwl.readLock().lock();
				rwl.writeLock().unlock();
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			rwl.readLock().unlock();
		}
		return instance;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章