1、什么是线程安全问题?
根据上篇文章中的购票代码可知,若出现重票,错票等问题,这都属于出现了线程安全问题。
2、出现线程安全问题的原因:
当某个线程还在操作车票的过程中,核心步骤还没有操作完成时,其他线程就参与进来也对车票进行了操作,这就导致了如上的线程安全问题。举个不太好但是形象的例子,某个公共厕所总共三个位置,你只能等里面的人解决完问题出来,下一个才能进去,如果里边的人还在解决,而下一个就强行进去了,岂不是乱套了?
3、如何去解决线程安全问题?
当一个线程a在操作ticket时,其他线程不能参与进来。知道线程a操作完ticket时,其他线程才可以开始操作提ticket。这种情况即使线程a出现了阻塞,其他线程也不能进来操作。通俗就是,只要厕所里面有人,就算他在里边睡觉,你也得等他睡完了才能进去。
4、如何理解解决线程安全的办法和单线程的区别?
虽然说解决线程安全过程中不允许其他线程进行操作,看似和单线程一致。多线程只是在处理关键的共享数据时会单线程操作,其他时候都是多线程运行操作,而单线程仅仅是一个线程走到底。?
5、具体方法:
①使用同步代码块
synchronize(同步监视器) {
需要被同步的代码?
}
通俗来讲同步监视器就是一把共用的锁,在上厕所时把门锁上,同时会显示红色有人,注意此处必须是同一把锁,否则进出wc以自身锁信号为准还是会出错乱套。
实现Runnable接口创建多线程,解决线程安全问题:?
class Windows implements Runnable{
private int ticket = 100;
//Object object = new Object(); 方式一:创建了一个Object对象作为唯一锁
@Override
public void run() {
//synchronized (object) {
synchronized (this) { //方式二:使用当前类对象作为唯一锁
while (true) {
if (ticket > 0) {
System.out.println("您购买的票号为:" + ticket);
ticket--;
} else
break;
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
Windows windows = new Windows();
Thread t1 = new Thread(windows);
Thread t2 = new Thread(windows);
Thread t3 = new Thread(windows);
t1.start();
t2.start();
t3.start();
}
}
子类继承Thread类创建多线程,解决线程安全问题:
class myThread extends Thread{
private int ticket = 100;
//static Object object = new Object(); //方式一:使用静态Object类对象作为唯一锁,必须加上static,否则三个对象对应三个Object类对象,不唯一
@Override
public void run() {
//synchronized (object) {
synchronized (Thread.class) { //方式二:使用当前类作为唯一锁,当前类也为对象
while (true) {
if (ticket > 0) {
System.out.println("您购买的票号为:" + ticket);
ticket--;
} else
break;
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
myThread my1 = new myThread();
myThread my2 = new myThread();
myThread my3 = new myThread();
my1.start();
my2.start();
my3.start();
}
}
②使用同步方法解决线程安全问题 ,将需要处理的代码块写进一个方法,方法用synchronized修饰。
同步方法解决实现Runnable接口创建的多线程的线程安全问题
class Windows1 implements Runnable{
private int ticket = 100;
Object object = new Object();
@Override
public void run() {
while (true) {
show();
if (ticket <= 0)
break;
}
}
//将操作共享数据关键代码用show()方法抽取出来,然后用synchronized修饰
private synchronized void show(){ //此时同步监视器为this
if (ticket > 0) {
System.out.println("您购买的票号为:" + ticket);
ticket--;
}
}
}
public class RunnableTest1 {
public static void main(String[] args) {
Windows windows = new Windows();
Thread t1 = new Thread(windows);
Thread t2 = new Thread(windows);
Thread t3 = new Thread(windows);
t1.start();
t2.start();
t3.start();
}
}
同步方法解决子类继承Thread类创建的多线程的线程安全问题:
class myThread1 extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
show();
if (ticket <= 0)
break;
}
}
//需要声明为static静态方法,这样保证三个对象调用的是同一个方法
private static synchronized void show() { //同步监视器为myThread1.class
if (ticket > 0) {
System.out.println("您购买的票号为:"+Thread.currentThread().getName() + "-"+ticket);
ticket--;
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
myThread1 my1 = new myThread1();
myThread1 my2 = new myThread1();
myThread1 my3 = new myThread1();
my1.start();
my2.start();
my3.start();
}
}
|