1.解决线程安全问题有三种方案:
1.1 同步代码块
syncnized(锁对象){
可能出现线程安全问题的代码,访问了共享数据的daima
}
注意:a.代码块中的锁对象,可以使用任意对象
b.必须保证多线程使用的锁对象是同一个
c.锁对象将同步代码块锁住,只让一个线程在同步代码块中执行
同步中的线程,没有执行完毕不会释放锁,,同步外的线程没有锁对象,进不去同步
thread.sleep() 进入休眠后会释放CPU的执行权,但不会释放锁对象,只有出了同步代码块才会释放锁对象
2. 同步方法
同步方法也会把方法内部的代码锁住,只让一个线程执行,锁对象就是实现类对象(new Runable(),也就是this)
静态的同步方法,锁对象不能是this,this是创建对象之后产生的,静态优先于对象,静态方法的锁对象是本类的class属性-->class文件对象
3. 锁机制
lock实现提供了比使用synchronized方法和语句更加广泛的锁定操作
lock l = new reentrantlock()
l.lock 在可能出现线程安全问题代码前,加上
l.unlock 在可能出现线程安全问题代码后,加上 这个更加建议放在finally中,无论怎样都释放锁,提高性能
package threaddemo; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /**创建线程执行的任务 * 这里以售卖三个窗口共同售卖100张火车票为例 * 三个窗口要共同售卖100张火车票,相当于三条线程访问共同的资源,存在数据安全问题。今天提出三个解决方案。 * @author Jeady * @Date 2019/8/2 */ public class lockTacket implements Runnable{ static int tacket = 100; //因为同步代码块中用到了静态同步,因此这里为了不影响效果,加上static Object obj = new Object(); Lock lock = new ReentrantLock(); public void run() { while (true){ //解决方案一:同步代码块 synchronized (obj){ if (tacket>0) { try { //线程休眠,释放CPU执行权,但并不一定释放锁对象,只有出了同步代码块才释放锁对象 Thread.sleep(10); System.out.println(Thread.currentThread().getName() + "正在销售第" + tacket + "张票"); tacket--; } catch (InterruptedException e) { e.printStackTrace(); } } } //demo1(); // demo2(); } } //解决方案二:同步方法 private static synchronized void demo1() { if (tacket>0){ try { //线程休眠,释放CPU执行权,但并不一定释放锁对象,只有出了同步代码块才释放锁对象 Thread.sleep(10); System.out.println(Thread.currentThread().getName()+"正在销售第"+tacket+"张票"); tacket--; } catch (InterruptedException e) { e.printStackTrace(); } } } //解决方案三:锁机制 private void demo2() { lock.lock(); //用在可能出现线程安全的代码之前 if (tacket>0){ try { Thread.sleep(10); System.out.println(Thread.currentThread().getName()+"正在销售第"+tacket+"张票"); tacket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock();//用在可能出现线程安全问题代码之后 } } } }
package threaddemo; /**定义三个线程 * @author Jeady * @Date 2019/8/2 */ public class ThreadRun01 { public static void main(String[] args) { lockTacket lockTacket = new lockTacket(); //创建三个线程 Thread t1 = new Thread(lockTacket); Thread t2 = new Thread(lockTacket); Thread t3 = new Thread(lockTacket); //开启三条线程 t1.start(); t2.start(); t3.start(); } }
效果如下: