java如何解决线程安全问题,一共有两种方式
1、同步代码块
synchronized (同步监视器) {
//需要同步的代码(操作共享数据的代码)
}
同步监视器:由一个对象来充当,哪个线程获取这个监视器,就可以执行括号里的代码。一般叫加锁
同步锁的作用,保证任何时候之后一个线程能够执行同步锁里的代码、
注意:implement Runnable接口和extends Thread类加锁的方式有点不同。如果是实现接口,那么就可以创建一个实现类,之后放在Thread的构造方法里就可以。这样保证了每次创建了一个共享数据。
但是继承Thread类就是每次都要new出新的对象,不管是数据还是什么都是自身有自身的,数据也好,锁也好。这时候为了保证数据的唯一性,都会用static来修饰此变量。
package com.thread.test; class Windos2 extends Thread{ static int ticketNum = 100; static Object obj = new Object(); @Override public void run() { // TODO Auto-generated method stub while (true) { synchronized (obj) { if (ticketNum > 0) { System.out.println(Thread.currentThread().getName() + "号售出第" + ticketNum--); } } } } } public class TextWindow2 extends Thread{ /** * @param args */ public static void main(String[] args) { Windos2 w1 = new Windos2(); Windos2 w2 = new Windos2(); Windos2 w3 = new Windos2(); w1.setName("1号售票口"); w2.setName("2号售票口"); w3.setName("3号售票口"); w1.start(); w2.start(); w3.start(); } }
实现接口
package com.thread.test; public class Window{ public static void main(String[] args) { TestWindow w = new TestWindow(); Thread w1 = new Thread(w); Thread w2 = new Thread(w); Thread w3 = new Thread(w); w1.setName("一号售票口"); w2.setName("2号售票口"); w3.setName("3号售票口"); w1.start(); w2.start(); w3.start(); } } class TestWindow implements Runnable{ int ticketNum = 100; @Override public void run() { while (true) { synchronized(this){ if(ticketNum>0){ System.out.println(Thread.currentThread().getName()+"号售出第"+ticketNum--); } } } } }
2、同步方法
private synchronized void show(){
}
把需要同步数据的代码放在同步方法里然后调用此方法就可以达到同步的效果。
同步方法看起来没有锁,其实它的锁就是当前对象,也就是this。所以在继承Thread类的时候达不到同步的效果