【Java多线程】多线程的线程安全及同步(synchronized)用法
2017-08-22 23:15
771 查看
Q:什么是线程安全问题?
A:当多个线程同时共享同一个全局变量或静态变量,改变变量的数据时,可能会发生数据冲突问题,也就是线程安全问题。读取变量不会发生数据冲突。
Q:当有线程安全问题时,应该怎样处理?
A:把对全局变量或静态变量做修改的代码放入同步代码块,即synchronized(){}。
PS:synchronized 修饰方法使用锁是当前this锁。synchronized 修饰静态方法使用锁是当前类的字节码文件。
运行结果片段
让线程每卖出一张票睡眠100毫秒
运行结果片段
这就是两个线程在同时操作一个变量,造成的线程安全问题。
运行结果片段
A:当多个线程同时共享同一个全局变量或静态变量,改变变量的数据时,可能会发生数据冲突问题,也就是线程安全问题。读取变量不会发生数据冲突。
Q:当有线程安全问题时,应该怎样处理?
A:把对全局变量或静态变量做修改的代码放入同步代码块,即synchronized(){}。
PS:synchronized 修饰方法使用锁是当前this锁。synchronized 修饰静态方法使用锁是当前类的字节码文件。
案例:售票系统,假设有两个窗口同时售票,使用多线程模拟售票。
SellTicket.javapublic class SellTicket implements Runnable{ // 100张票 private int ticketCount = 100; // 使用线程模拟售票窗口 @Override public void run() { // 死循环,窗口不停卖票 while (true) { // 未在操作变量的代码加锁(同步) // 如果票数为零,则跳出循环,结束线程(关闭窗口,停止售票) if (ticketCount > 0) { // try { // Thread.sleep(0); // } catch (Exception e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticketCount + 1) + "张票."); ticketCount--; } else { break; } } } public static void main(String[] args) { // 单例,只有一个ticketCount SellTicket st = new SellTicket(); // 创建两个线程并运行 Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); } }
运行结果片段
Thread-0,出售 第1张票. Thread-0,出售 第2张票. Thread-0,出售 第3张票. Thread-0,出售 第4张票. Thread-0,出售 第5张票. Thread-1,出售 第1张票. Thread-1,出售 第7张票. Thread-1,出售 第8张票. Thread-1,出售 第9张票.
Thread-1,出售 第98张票. Thread-1,出售 第99张票. Thread-1,出售 第100张票. Thread-0,出售 第40张票.可以看到线程0已经卖出了第1张票,可是线程1也卖出了第1张票,而最后线程1已经卖出了第100张票,线程0又卖出了第40张票。
让线程每卖出一张票睡眠100毫秒
// 如果票数为零,则跳出循环,结束线程(关闭窗口,停止售票) if (ticketCount > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticketCount + 1) + "张票."); ticketCount--; } else { break; }
运行结果片段
Thread-1,出售 第99张票. Thread-0,出售 第100张票. Thread-1,出售 第101张票.这次除了出现以上的情况,还卖出了第101张票。
这就是两个线程在同时操作一个变量,造成的线程安全问题。
怎么让线程安全?使用同步代码块(加锁)
SellTicket.javapublic class SellTicket implements Runnable{
// 100张票
pri
4000
vate int ticketCount = 100;
// 同步代码块的锁
private Object obj = new Object();
// 使用线程模拟售票窗口
@Override
public void run() {
// 死循环,窗口不停卖票
while (true) {
// 在操作变量的代码加obj锁(同步),当某个线程开始运行里面代码时,会得到锁。
// 其他线程如果想运行同样代码,需等得到锁的代码运行完毕解锁后,再得到锁执行。
synchronized(obj) {
// 如果票数为零,则跳出循环,结束线程(关闭窗口,停止售票) if (ticketCount > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticketCount + 1) + "张票."); ticketCount--; } else { break; }
}
}
}
public static void main(String[] args) {
// 单例,只有一个ticketCount
SellTicket st = new SellTicket();
// 创建两个线程并运行
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
}
}
运行结果片段
Thread-0,出售 第92张票. Thread-0,出售 第93张票. Thread-0,出售 第94张票. Thread-0,出售 第95张票. Thread-0,出售 第96张票. Thread-0,出售 第97张票. Thread-1,出售 第98张票. Thread-1,出售 第99张票. Thread-1,出售 第100张票.同步后线程安全问题解决了。
相关文章推荐
- Java基础-多线程-③线程同步之synchronized
- 【Java面试题】26 多线程有几种实现方法?同步有几种实现方法? 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
- JAVA线程安全之synchronized关键字的正确用法
- Java笔记3 多线程<1>线程概述、多线程的创建、多线程的安全问题、静态同步函数的锁、死锁
- Java基础-多线程-③线程同步之synchronized
- JAVA线程安全之synchronized关键字的正确用法
- java 多线程 同步 synchronized 的个人理解和用法
- JAVA多线程--线程的同步安全
- JAVA线程安全之synchronized关键字的正确用法
- JAVA线程安全之synchronized关键字的正确用法
- java多线程学习一线程安全之内存、synchronized、volatile
- Java多线程,线程同步synchronized,线程死锁【线程池常规用法】多线程并发处理
- Java基础-多线程-③线程同步之synchronized
- Java基础-多线程-③线程同步之synchronized
- [Java]Java多线程数据安全(同步线程的方法)
- java线程同步-synchronized锁用法
- 黑马程序员-19-java基础-多线程(2)-死锁与线程间通信(synchronized与Lock的区别及各自用法)
- JAVA线程安全之synchronized关键字的正确用法
- Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)
- java 多线程系列之线程安全和synchronized