🍔生命周期
🎄线程的安全问题
发现有两个问题,相同的票出现了多次,出现了超出范围的票
🏳️🌈原因
首先线程被线程一抢走了
线程一执行到了sleep,会休眠10ms,然后ticket+1,变为了1
然后线程被线程二抢走了
线程二执行到了sleep,会休眠10ms,然后ticket+1,变为了2
然后线程被线程三抢走了
线程三执行到了sleep,会休眠10ms,然后ticket+1,变为了3
现在ticket是3,就会打印3次ticket=3的结果
⭐改进方法
我们把下面的代码给框起来,设置一个线程执行完这个代码块后,其他线程才能执行
🌺同步代码块
把操作共享数据的代码给锁起来
synchronizd(锁){
操作共享数据的代码
}
- 锁默认打开,有一个线程进去了,锁自动关闭
- 里面的代码全部执行完毕,线程出来,锁自动打开
我们把之前的代码块用锁包围起来康康效果如何
MyThread.java
public class MyThread extends Thread {
//表示这个类的所有对象,都共享ticket数据
static int ticket = 0;//0~99
//锁的对象,一定要是唯一的
static Object obj=new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket < 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket++;
System.out.println(getName() + "正在卖第" + ticket + "张票");
} else {
break;
}
}
}
}
}
Demo1.java
package IODemo6;
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//创建线程对象
MyThread t1=new MyThread();
MyThread t2=new MyThread();
MyThread t3=new MyThread();
//起名字
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
//开启线程
t1.start();
t2.start();
t3.start();
}
}
⭐细节
- 锁必须要写到循环里面
- 锁对象必须唯一
🌺同步方法
就是把synchronized关键字加到方法上
修饰符 synchronized 返回值类型 方法名(方法参数){
......
}
MyRunnable.java
public class MyRunnable implements Runnable{
int ticket=0;
@Override
public void run() {
while (true){
//同步方法
if (method()) break;
}
}
public synchronized boolean method(){
//共享数据 到了末尾
if (ticket==100){
return true;
}else {
//共享数据 没有到末尾
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket++;
System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票!!!");
}
return false;
}
}
ThreadDemo.java
public class ThreadDemo {
public static void main(String[] args) {
MyRunnable mr=new MyRunnable();
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
Thread t3=new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}