开始时间 2018年8月12日20:09:02
结束时间 2018年8月12日22:44:44
累计时间 2小时
线程的安全问题
原因;
操作同一个数据中间切换的时候,一个线程操作共享数据的时候,未执行完的情况下 ,另外的线程参与进来,导致安全问题。
解决方案;
一个线程操作共享数据完毕之后,其他线程才可以操作。 比如上厕所要排队一个一个来。
方式一 同步代码块
synchronized(同步监视器){ * //需要被同步的代码块(即为操作共享数据的代码) * } * 1.共享数据:多个线程共同操作的同一个数据(变量) * 2.同步监视器:由一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁 * 要求:所有的线程必须共用同一把锁! * 注:在实现的方式中,考虑同步的话,可以使用this来充当锁。但是在继承的方式中, 慎用this: 1 在一般的方法中 可以使用。 2 在静态类的话当前类本身充当锁。 原理如下 一个线程抢到锁之后 其他线程在当前线程结束之后才可以进入操作代码块的语句。 锁可以由任意类对象充当~ 如果使用this的话。 三个对象各自对象的锁 还是会出现安全问题。
注意共同操作的数据 不能是局部变量 所有线程必须共用同一把锁(即 锁要用static 修饰)
class Window2 implements Runnable {
int ticket = 100;// 共享数据
// Object obj = new Object();
public void run() {
// Animal a = new Animal();//局部变量
while (true) {
synchronized (this) {//this表示当前对象,本题中即为w
if (ticket > 0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "售票,票号为:" + ticket--);
}
}
}
}
}
public class TestWindow2 {
public static void main(String[] args) {
Window2 w = new Window2();
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 Animal{
}
方式二 同步方法
将操作共享数据的方法声明为synchronized。即此方法为同步方法,能够保证当其中一个线程执行 * 此方法时,其它线程在外等待直至此线程执行完此方法。 * 同步方法的锁:this
线程的同步的弊端:由于同一个时间只能有一个线程访问共享数据,效率变低了。
class Window4 implements Runnable {
int ticket = 100;// 共享数据
public void run() {
while (true) {
show();
}
}
public synchronized void show() {
if (ticket > 0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "售票,票号为:"
+ ticket--);
}
}
}
public class TestWindow4 {
public static void main(String[] args) {
Window4 w = new Window4();
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();
}
}
单例模式懒汉式线程安全
补充
单例模式 两种比较https://blog.csdn.net/ysk_xh_521/article/details/77394683
&双重锁模式 https://blog.csdn.net/zhangliangzi/article/details/52438401
实际开发比较推荐双重锁
//关于懒汉式的线程安全问题:使用同步机制
//对于一般的方法内,使用同步代码块,可以考虑使用this。
//对于静态方法而言,使用当前类本身充当锁。
class Singleton {
private Singleton() {
}
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
public class TestSingleton {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
// Class clazz = Singleton.class;
}
}
释放锁