首页 > 代码库 > 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();                    }            }    }
View Code

要实现同步,可在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();        }            }    }
View Code

 

线程间协作

假设创建并启动两个任务,一个用来向账户中存款,另一个从同一个账户提款。当提款的数额大于账户的当前余额时,提款线程必须等待。不管什么时候,只要向账户心存入一笔资金,存储线程必须通知提取线程重新尝试。如果余额仍未达到提款的数额,提取线程必须继续等待存入更多的资金。

技术分享
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();            }        }            }    }
View Code

 

生产者消费者模型

假设使用缓冲区存储证书。缓冲区大小受限。缓冲区提供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;        }            }    }
View Code

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 没有死锁!");                }            }        }    }    }
View Code

输出为:

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 没有死锁!");                }            }        }    }    }
View Code

 

Java多线程