Synchronized是java中的关键字,一种同步锁,用来修饰以下对象:
1.修饰一个代码块:被修饰的代码块称为同步语句块,其作用的范围是{}括起来的代码,作用的对象是调用这个代码块的对象
2.修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象
3.修饰一个静态方法:其作用的范围是整个方法,作用的对象是这个类的所有方法
4.修饰一个类:其作用的范围是synchronized(括号里面的部分),作用的对象是这个类的所有对象
public static void main(String[] args) {
Runnable ticking = new Ticketing();
// 实例化线程对象
Thread thread1 = new Thread(ticking);
Thread thread2 = new Thread(ticking);
Thread thread3 = new Thread(ticking);
Thread thread4 = new Thread(ticking);
// 开启启动线程
thread1.start(); // 启动第Thread-0窗口
thread2.start(); // 启动第Thread-1窗口
thread3.start(); // 启动第Thread-2窗口
thread4.start(); // 启动第Thread-3窗口
}
static class Ticketing implements Runnable {
/**
* 模拟票的总算 10张票
*/
private int ticket = 10;
private boolean isRun = true;
@Override
public void run() {
while (isRun) {
if (ticket > 0) {
// 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
} else {
isRun = false;
}
}
}
}
运行结果:
名称:Thread-3窗口卖出第10张票
名称:Thread-1窗口卖出第10张票
名称:Thread-0窗口卖出第10张票
名称:Thread-2窗口卖出第10张票
名称:Thread-0窗口卖出第6张票
名称:Thread-2窗口卖出第6张票
名称:Thread-3窗口卖出第6张票
名称:Thread-1窗口卖出第5张票
名称:Thread-1窗口卖出第2张票
名称:Thread-0窗口卖出第2张票
名称:Thread-3窗口卖出第2张票
名称:Thread-2窗口卖出第2张票
名称:Thread-1窗口卖出第-2张票
很明显,乱的很,这里是因为哪个线程先有执行权,就执行哪个线程,都是随机的
加上synchronized方法:
synchronized (this) {
if (ticket > 0) {
// 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
} else {
isRun = false;
}
}
运行结果:
名称:Thread-0窗口卖出第10张票
名称:Thread-0窗口卖出第9张票
名称:Thread-0窗口卖出第8张票
名称:Thread-0窗口卖出第7张票
名称:Thread-0窗口卖出第6张票
名称:Thread-3窗口卖出第5张票
名称:Thread-3窗口卖出第4张票
名称:Thread-3窗口卖出第3张票
名称:Thread-3窗口卖出第2张票
名称:Thread-2窗口卖出第1张票
这样子的结果就很满意了,这是因为加入了同步代码块的代码synchronized,只要同步代码块里面的代码没有执行完,就不准其他线程进来执行,保证了多线程操作共享数据的安全性。
(参考:https://www.cnblogs.com/android-deli/p/10227614.html 整理学习)