1.同步机制:
java任意类型的对象都有一个标志位该标志位有0、1两种状态,其开始状态为1,当某个状态执行了synchronized(object)语句后object对象的标志位变为0状态,直到执行完整个synchronized语句中的代码,该对象的标志位又变回1状态。
当一个线程执行到synchronized(object)语句块时,先检查object对象的标志位,若为0表示有另外的线程正在执行synchronized(object)语句块,那么这个线程将暂时阻塞,让出cpu资源,直到另外的线程执行完相关代码,并将对象的标志位重新变为1,则这个线程的阻塞就被取消,这个线程继续运行,这个线程将对象标志位变为0,以防其他线程进入到相关代码中。
2.实例:
机票模拟程序:三个售票窗口一同售票
线程安全问题存在的原因:由于线程在操作共享数据的过程,未执行完毕的情况下,另外的线程参与进来导致安全问题
多线程开发线程安全问题:保证安全的关键就是代码的原子性,所谓原子性是指一个操作要不执行完,要不不执行,中途不可以中断,保持同步。
解决方法:
- 方法一:同步代码块synchronized(object){容易出现问题的代码…},其中object可以使任意类型的对象
- 方法二:同步方法
3.代码
- 实现接口——同步代码块
public class Test2 {
public static void main(String[] args) {
TicketWindow tw = new TicketWindow();
Thread t1 = new Thread(tw);//窗口一
Thread t2= new Thread(tw);//窗口二
Thread t3 = new Thread(tw);//窗口三
t1.start();//多线程
t2.start();
t3.start();
}
}
//定义窗口类:实现接口-同步代码块
class TicketWindow implements Runnable{
//一共2000张机票
//private static int number = 10;
int number = 10;//声明属性的修饰符没有同步的作用,所以这样声明属性和以上声明属性是一致的
//private int number = 10;//效果一样
@Override
public void run() {
//循环打印输出出售机票
while(true){
//同步代码块,使用synchronized关键字保证其原子性,关键字synchronized的意思就是同步
//this是对象锁
synchronized(this){
//判断是否还有机票
if(number > 0){
//提示售票信息,Thread.currentThread().getName()获得相称的名字
System.out.println(Thread.currentThread().getName()+"在售第"+number+"机票");
number--;
}else{
break;
}
}
//一个线程执行完,立即休眠1秒钟,另一个线程会立即执行同步代码块
//每隔一秒休眠一次
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
//非同步的代码
}
}
}
- 继承父类–同步代码块
- 1.实现同步保证线程安全,考虑使用同步机制,
- 2.同步在实现多线程的两种方法:实现接口的方法线程锁可以使用this代表当前对象,继承父类的方法线程锁慎用this,因为在继承中new了多个对象
- 3.使用同步代码块方法
public class Test3 {
public static void main(String[] args) {
Number2 n1 = new Number2();
Number2 n2 = new Number2();
Number2 n3 = new Number2();
n1.setName("线程1");
n2.setName("线程2");
n3.setName("线程3");
n1.start();
n2.start();
n3.start();
}
}
//继承父类--同步代码块
class Number2 extends Thread{
//创建根基类对象,此对象属于成员属性,每个对象都有的属性,必须使用静态修饰成共用的属性,才能实现锁的作用
static Object obj = new Object();
static int number = 20;//属性设置为静态,遮掩两个对象就可共用一个number属性
@Override
public void run() {
//两件事:1.同步number数字输出并减减,2.数字减一
while(true){
synchronized (obj) {
if (number > 0) {
System.out.println("我是"
+ Thread.currentThread().getName() + ":"
+ number--);
} else {
break;
}
}
}
}
}