活动地址:CSDN21天学习挑战赛
目录
线程安全的解决措施
1、问题:卖票过程中出现重票、错票
2、原因:当某个线程操作车票的过程中,尚未完成操作时,其他线程参与进来,也操作车票
3、解决:当一个线程A在操作ticket,其他线程不能参与进来, 直到线程A操作完ticket时,其他线程才可以开始操作ticket,即使线程A出现了阻塞也不能被改变
4、在java中,通过同步机制,来解决线程安全问题
5、同步的方式解决了线程的安全问题
操作同步代码时,只能有一个线程参与。相当于是一个单线程的过程,效率低
**
方式一:同步代码块
1,概述
synchronized(同步监视器){
//需要被同步的代码
}
说明:
操作共享数据的代码,即为需要被同步的代码。(不能包含代码多了,也不能包含代码少了)
共享数据:多个线程共同操作的变量,例:ticket(车票)就是共享数据
同步监视器:俗称:锁。任何一个类的对象都可以充当锁
要求:多个线程必须共用同一把锁
补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器
2,使用同步代码块解决继承Thread类的方式的线程安全问题
在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视
3,举例
public class Test { public static void main(String[] args) { Window t1 = new Window(); Window t2 = new Window(); Window t3 = new Window(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } class Window extends Thread{ private static int ticket = 100;//设置为静态,实现变量的全局共享 private static Object obj = new Object();//因为生产多个对象 @Override public void run() { while (true){ //synchronized (obj) { synchronized (Window.class){ // synchronized (this){ //错误的方式:this代表着t1,t2,t3三个对象 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "票号为:" + ticket); ticket--; } else { break; } } } } }
**
方式二:同步方法
1,概述
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
1、同步方法仍然涉及到同步监视器,只是不需要我们显式声明
2、非静态的同步方法,同步监视器是:this
3、静态同步方法,同步监视器是:当前类的本身
2,使用同步方法解决实现Runnable接口的线程安全问题
public class Test { public static void main(String[] args) { Window3 w = new Window3();//不用将ticket设为静态 Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } class Window3 implements Runnable{ private int ticket = 100; @Override public void run() { while (true) { show(); } } private synchronized void show() {//它的同步监视器是this //synchronized (this) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "票号为:"+ticket); ticket--; } //} } }
3,使用同步方法处理继承Thread类的方式中的线程安全问题
public class Test { public static void main(String[] args) { Window4 t1 = new Window4(); Window4 t2 = new Window4(); Window4 t3 = new Window4(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } class Window extends Thread{ private static int ticket = 100;//设置为静态,实现变量的全局共享 @Override public void run() { while (true){ show(); } } private static synchronized void show(){ //同步监视器:Window.class //private synchronized void show(){ //同步监视器:t1,t2,t3 错误 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "票号为:" + ticket); ticket--; } } }
提醒:在发布作品前请把不用的内容删掉(活动地址请保留)
本文含有隐藏内容,请 开通VIP 后查看