目录
正文
多个执行线程共享一个资源的情景,是并发编程中最常见的情景之一。多个线程读或者写相同的数据等情况时可能会导致数据不一致。为了解决这些问题,引入了临界区概念。临界区是一个用以访问共享资源的代码块,这个代码块在同一时间内只允许一个线程执行。
使用synchronized实现同步方法
- 在方法声明中加入synchronized关键字
-
1 public synchronized void addAmount(double amount) { 2 }
- 在代码块中使用synchronized关键字,obj一般可以使用this关键字表示本类对象
-
1 synchronized(obj){ 2 }
1 public class Account {
2 private double balance;
3 public double getBalance() {
4 return balance;
5 }
6 public void setBalance(double balance) {
7 this.balance = balance;
8 }
9 public synchronized void addAmount(double amount) {
10 double tmp=balance;
11 try {
12 Thread.sleep(10);
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 tmp+=amount;
17 balance=tmp;
18 }
19 public synchronized void subtractAmount(double amount) {
20 double tmp=balance;
21 try {
22 Thread.sleep(10);
23 } catch (InterruptedException e) {
24 e.printStackTrace();
25 }
26 tmp-=amount;
27 balance=tmp;
28 }
29 }
1 public class Main {
2 public static void main(String[] args) {
3 Account account=new Account();
4 account.setBalance(1000);
5 Company company=new Company(account);
6 Thread companyThread=new Thread(company);
7 Bank bank=new Bank(account);
8 Thread bankThread=new Thread(bank);
9
10 companyThread.start();
11 bankThread.start();
12 try {
13 companyThread.join();
14 bankThread.join();
15 System.out.printf("Account : Final Balance: %f\n",account.getBalance());
16 } catch (InterruptedException e) {
17 e.printStackTrace();
18 }
19 }
20 }
使用非依赖属性实现同步
1 public class Cinema {
2 private long vacanciesCinema1;
3 private long vacanciesCinema2;
4
5 private final Object controlCinema1, controlCinema2;
6
7 public Cinema(){
8 controlCinema1=new Object();
9 controlCinema2=new Object();
10 vacanciesCinema1=20;
11 vacanciesCinema2=20;
12 }
13
14 public boolean sellTickets1 (int number) {
15 synchronized (controlCinema1) {
16 if (number<vacanciesCinema1) {
17 vacanciesCinema1-=number;
18 return true;
19 } else {
20 return false;
21 }
22 }
23 }
24
25 public boolean sellTickets2 (int number){
26 synchronized (controlCinema2) {
27 if (number<vacanciesCinema2) {
28 vacanciesCinema2-=number;
29 return true;
30 } else {
31 return false;
32 }
33 }
34 }
35
36 public boolean returnTickets1 (int number) {
37 synchronized (controlCinema1) {
38 vacanciesCinema1+=number;
39 return true;
40 }
41 }
42 public boolean returnTickets2 (int number) {
43 synchronized (controlCinema2) {
44 vacanciesCinema2+=number;
45 return true;
46 }
47 }
48 public long getVacanciesCinema1() {
49 return vacanciesCinema1;
50 }
51 public long getVacanciesCinema2() {
52 return vacanciesCinema2;
53 }
54 }
在同步块中使用条件(wait(),notify(),notifyAll())
- 上述三个方法都是Object 类的方法。
- 上述三个方法都必须在同步代码块中使用。
1 public synchronized void set(){
2 while (storage.size()==maxSize){
3 try {
4 wait();
5 } catch (InterruptedException e) {
6 e.printStackTrace();
7 }
8 }
9 storage.add(new Date());
10 System.out.printf("Set: %d\n", storage.size());
11 notify();
12 }
13 public synchronized void get(){
14 while (storage.size()==0){
15 try {
16 wait();
17 } catch (InterruptedException e) {
18 e.printStackTrace();
19 }
20 }
21 System.out.printf("Get: %d: %s\n",storage.size(),((LinkedList<?>)storage).poll());
22 notify();
23 }
使用锁实现同步
1 public class PrintQueue {
2 private final Lock queueLock=new ReentrantLock();
3
4 public void printJob(Object document){
5 queueLock.lock();
6
7 try {
8 Long duration=(long)(Math.random()*10000);
9 System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n",Thread.currentThread().getName(),(duration/1000));
10 Thread.sleep(duration);
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 } finally {
14 queueLock.unlock();
15 }
16 }
17 }
1 private final Lock queueLock=new ReentrantLock();
1 queueLock.lock();
1 queueLock.unlock();
使用读写锁实现同步数据访问
在锁中使用多条件(Multri Condition)
1 private Condition lines;
2 private Condition space;
3 */
4 public void insert(String line) {
5 lock.lock();
6 try {
7 while (buffer.size() == maxSize) {
8 space.await();
9 }
10 buffer.offer(line);
11 System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread()
12 .getName(), buffer.size());
13 lines.signalAll();
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 } finally {
17 lock.unlock();
18 }
19 }
20 public String get() {
21 String line=null;
22 lock.lock();
23 try {
24 while ((buffer.size() == 0) &&(hasPendingLines())) {
25 lines.await();
26 }
27
28 if (hasPendingLines()) {
29 line = buffer.poll();
30 System.out.printf("%s: Line Readed: %d\n",Thread.currentThread().getName(),buffer.size());
31 space.signalAll();
32 }
33 } catch (InterruptedException e) {
34 e.printStackTrace();
35 } finally {
36 lock.unlock();
37 }
38 return line;
39 }
正文
多个执行线程共享一个资源的情景,是并发编程中最常见的情景之一。多个线程读或者写相同的数据等情况时可能会导致数据不一致。为了解决这些问题,引入了临界区概念。临界区是一个用以访问共享资源的代码块,这个代码块在同一时间内只允许一个线程执行。
使用synchronized实现同步方法
- 在方法声明中加入synchronized关键字
-
1 public synchronized void addAmount(double amount) { 2 }
- 在代码块中使用synchronized关键字,obj一般可以使用this关键字表示本类对象
-
1 synchronized(obj){ 2 }
1 public class Account {
2 private double balance;
3 public double getBalance() {
4 return balance;
5 }
6 public void setBalance(double balance) {
7 this.balance = balance;
8 }
9 public synchronized void addAmount(double amount) {
10 double tmp=balance;
11 try {
12 Thread.sleep(10);
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 tmp+=amount;
17 balance=tmp;
18 }
19 public synchronized void subtractAmount(double amount) {
20 double tmp=balance;
21 try {
22 Thread.sleep(10);
23 } catch (InterruptedException e) {
24 e.printStackTrace();
25 }
26 tmp-=amount;
27 balance=tmp;
28 }
29 }
1 public class Main {
2 public static void main(String[] args) {
3 Account account=new Account();
4 account.setBalance(1000);
5 Company company=new Company(account);
6 Thread companyThread=new Thread(company);
7 Bank bank=new Bank(account);
8 Thread bankThread=new Thread(bank);
9
10 companyThread.start();
11 bankThread.start();
12 try {
13 companyThread.join();
14 bankThread.join();
15 System.out.printf("Account : Final Balance: %f\n",account.getBalance());
16 } catch (InterruptedException e) {
17 e.printStackTrace();
18 }
19 }
20 }
使用非依赖属性实现同步
1 public class Cinema {
2 private long vacanciesCinema1;
3 private long vacanciesCinema2;
4
5 private final Object controlCinema1, controlCinema2;
6
7 public Cinema(){
8 controlCinema1=new Object();
9 controlCinema2=new Object();
10 vacanciesCinema1=20;
11 vacanciesCinema2=20;
12 }
13
14 public boolean sellTickets1 (int number) {
15 synchronized (controlCinema1) {
16 if (number<vacanciesCinema1) {
17 vacanciesCinema1-=number;
18 return true;
19 } else {
20 return false;
21 }
22 }
23 }
24
25 public boolean sellTickets2 (int number){
26 synchronized (controlCinema2) {
27 if (number<vacanciesCinema2) {
28 vacanciesCinema2-=number;
29 return true;
30 } else {
31 return false;
32 }
33 }
34 }
35
36 public boolean returnTickets1 (int number) {
37 synchronized (controlCinema1) {
38 vacanciesCinema1+=number;
39 return true;
40 }
41 }
42 public boolean returnTickets2 (int number) {
43 synchronized (controlCinema2) {
44 vacanciesCinema2+=number;
45 return true;
46 }
47 }
48 public long getVacanciesCinema1() {
49 return vacanciesCinema1;
50 }
51 public long getVacanciesCinema2() {
52 return vacanciesCinema2;
53 }
54 }
在同步块中使用条件(wait(),notify(),notifyAll())
- 上述三个方法都是Object 类的方法。
- 上述三个方法都必须在同步代码块中使用。
1 public synchronized void set(){
2 while (storage.size()==maxSize){
3 try {
4 wait();
5 } catch (InterruptedException e) {
6 e.printStackTrace();
7 }
8 }
9 storage.add(new Date());
10 System.out.printf("Set: %d\n", storage.size());
11 notify();
12 }
13 public synchronized void get(){
14 while (storage.size()==0){
15 try {
16 wait();
17 } catch (InterruptedException e) {
18 e.printStackTrace();
19 }
20 }
21 System.out.printf("Get: %d: %s\n",storage.size(),((LinkedList<?>)storage).poll());
22 notify();
23 }
使用锁实现同步
1 public class PrintQueue {
2 private final Lock queueLock=new ReentrantLock();
3
4 public void printJob(Object document){
5 queueLock.lock();
6
7 try {
8 Long duration=(long)(Math.random()*10000);
9 System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n",Thread.currentThread().getName(),(duration/1000));
10 Thread.sleep(duration);
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 } finally {
14 queueLock.unlock();
15 }
16 }
17 }
1 private final Lock queueLock=new ReentrantLock();
1 queueLock.lock();
1 queueLock.unlock();
使用读写锁实现同步数据访问
在锁中使用多条件(Multri Condition)
1 private Condition lines;
2 private Condition space;
3 */
4 public void insert(String line) {
5 lock.lock();
6 try {
7 while (buffer.size() == maxSize) {
8 space.await();
9 }
10 buffer.offer(line);
11 System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread()
12 .getName(), buffer.size());
13 lines.signalAll();
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 } finally {
17 lock.unlock();
18 }
19 }
20 public String get() {
21 String line=null;
22 lock.lock();
23 try {
24 while ((buffer.size() == 0) &&(hasPendingLines())) {
25 lines.await();
26 }
27
28 if (hasPendingLines()) {
29 line = buffer.poll();
30 System.out.printf("%s: Line Readed: %d\n",Thread.currentThread().getName(),buffer.size());
31 space.signalAll();
32 }
33 } catch (InterruptedException e) {
34 e.printStackTrace();
35 } finally {
36 lock.unlock();
37 }
38 return line;
39 }