首页 > 代码库 > Java多线程
Java多线程
线程同步
假设创建并启动100个线程,每个线程都往同一个账户中添加一个便士。非同步状态下得到的结果是2。
package com.halin.demo;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class AccountWithoutSync { private static Account account = new Account(); public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 100; i++) { executor.execute(new AddAPennyTask()); } executor.shutdown(); while (!executor.isTerminated()) { } System.out.println("What is balance ? " + account.getBalance()); } private static class AddAPennyTask implements Runnable { public void run() { account.deposit(1); } } private static class Account { private static Lock lock = new ReentrantLock(); private int balance = 0; public int getBalance() { return balance; } public void deposit(int amount) { // lock.lock(); int newBalance = balance + amount; try { Thread.sleep(5); } catch (InterruptedException ex) { } balance = newBalance; // lock.unlock(); } } }
要实现同步,可在deposit方法前添加关键字synchronized来实现一个隐式锁,也可以直接添加显式锁来lock()和unlock()。显式锁对同步具有状态的线程更加直观和灵活。只有一个许可的信号量也可以用来模拟一个相互排斥的锁。
private static class Account { private static Semaphore semaphore = new Semaphore(1); private int balance = 0; public int getBalance() { return balance; } public void deposit(int amount) { try { semaphore.acquire(); int newBalance = balance + amount; Thread.sleep(5); balance = newBalance; } catch (InterruptedException ex) { } finally { semaphore.release(); } } }
线程间协作
假设创建并启动两个任务,一个用来向账户中存款,另一个从同一个账户提款。当提款的数额大于账户的当前余额时,提款线程必须等待。不管什么时候,只要向账户心存入一笔资金,存储线程必须通知提取线程重新尝试。如果余额仍未达到提款的数额,提取线程必须继续等待存入更多的资金。
package com.halin.demo;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ThreadCooperation { private static Account account = new Account(); public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new DepositTask()); executor.execute(new WithdrawTask()); executor.shutdown(); System.out.println("Thread 1\t\tThread 2\t\tBalance"); } public static class DepositTask implements Runnable { public void run() { try { while (true) { account.deposit((int) (Math.random() * 10) + 1); Thread.sleep(1000); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } public static class WithdrawTask implements Runnable { public void run() { while (true) { account.withDraw((int) (Math.random() * 10) + 1); } } } public static class Account { private static Lock lock = new ReentrantLock(); private static Condition newDeposit = lock.newCondition(); private int balance = 0; public int getBalance() { return balance; } public void withDraw(int amount) { lock.lock(); try { while (balance < amount) { newDeposit.await(); } balance -= amount; System.out.println("\t\t\tWithdraw " + amount + "\t\t" + getBalance()); } catch (InterruptedException ex) { ex.printStackTrace(); } finally { lock.unlock(); } } public void deposit(int amount) { lock.lock(); try { balance += amount; System.out.println("Deposit " + amount + "\t\t\t\t\t" + getBalance()); newDeposit.signalAll(); } finally { lock.unlock(); } } } }
生产者消费者模型
假设使用缓冲区存储证书。缓冲区大小受限。缓冲区提供write(int)方法将一个int值添加到缓冲区,还提供方法read()从缓冲区中读取和删除一个int值。为了同步这个操作,使用具有两个条件的锁:notEmpty(即缓冲区非空)和notFull(即缓冲区未满)。当一个任务向缓冲区添加一个int时,如果缓冲区是满的,那么任务将会等待notFull状态。当任务从缓冲区中删除一个int时,如果缓冲区是空的,那么任务将等待notEmpty状态。
package com.halin.demo;import java.util.LinkedList;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ConsumerProducer { private static Buffer buffer = new Buffer(); public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new ProducerTask()); executor.execute(new ConsumerTask()); executor.shutdown(); } private static class ProducerTask implements Runnable { public void run() { try { int i = 1; while (true) { System.out.println("Producer writes " + i); buffer.write(i++); Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } private static class ConsumerTask implements Runnable { public void run() { try { int i = 1; while (true) { System.out.println("\t\t\tConsumer reads " + buffer.read()); Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } private static class Buffer { private static final int CAPACITY = 1; private LinkedList<Integer> queue = new LinkedList<Integer>(); private static Lock lock = new ReentrantLock(); private static Condition notEmpty = lock.newCondition(); private static Condition notFull = lock.newCondition(); public void write(int value) { lock.lock(); try { while (queue.size() == CAPACITY) { System.out.println("Wait for notFull condition"); notFull.await(); } queue.offer(value); notEmpty.signal(); } catch (InterruptedException ex) { ex.printStackTrace(); } finally { lock.unlock(); } } public int read() { int value = http://www.mamicode.com/0; lock.lock(); try { while (queue.isEmpty()) { System.out.println("\t\tWait for notEmpty condition"); notEmpty.await(); } value = queue.remove(); notFull.signal(); } catch (InterruptedException ex) { ex.printStackTrace(); } finally { lock.unlock(); } return value; } } }
ArrayBlockingQueue已现实同步,可代替Buffer,减少人工编码。
避免死锁
有时两个或多个线程需要锁定几个共享对象,这时可能引起死锁。也就是说,每个线程已经锁定一个对象,正在等待锁定另一个对象。考虑有两个线程和两个锁的情形。线程1锁定了locker1,等待locker2。线程2锁定了locker2,等待locker1。每个线程都等待另一个线程释放自己需要的锁,结果导致两个线程都无法继续运行。
package com.halin.demo;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Deadlock { public static byte[] locker1 = new byte[0]; public static byte[] locker2 = new byte[0]; public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(100); for(int i = 0; i < 50; i++){ executor.execute(new DeadlockTask1()); executor.execute(new DeadlockTask2()); } executor.shutdown(); while(!executor.isTerminated()){ } System.exit(0); } private static class DeadlockTask1 implements Runnable { public void run() { synchronized(locker1){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask1 获得锁 locker1"); synchronized(locker2){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask1 获得锁 locker2 没有死锁!"); } } } } private static class DeadlockTask2 implements Runnable { public void run() { synchronized(locker2){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask2 获得锁 locker2"); synchronized(locker1){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask2 获得锁 locker1 没有死锁!"); } } } } }
输出为:
DeadlockTask1 获得锁 locker1DeadlockTask2 获得锁 locker2
如果Thread.sleep(1000)的话,可能就不会死锁,因为处理太快了。
解决方法很简单,为共享资源的锁排序,按序加锁。先锁定locker1,再锁定locker2。
package com.halin.demo;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class LockInOrder { public static byte[] locker1 = new byte[0]; public static byte[] locker2 = new byte[0]; public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(100); for(int i = 0; i < 50; i++){ executor.execute(new DeadlockTask1()); executor.execute(new DeadlockTask2()); } executor.shutdown(); while(!executor.isTerminated()){ } System.exit(0); } private static class DeadlockTask1 implements Runnable { public void run() { synchronized(locker1){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask1 获得锁 locker1"); synchronized(locker2){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask1 获得锁 locker2 没有死锁!"); } } } } private static class DeadlockTask2 implements Runnable { public void run() { synchronized(locker1){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask2 获得锁 locker2"); synchronized(locker2){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("DeadlockTask2 获得锁 locker1 没有死锁!"); } } } } }
Java多线程