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();
}
}
效果如下: