使用synchronized修饰的方法控制对类成员变量的访问
访问修饰符synchronized 返回类型 方法名(参数列表){......}
或者synchronized访问修饰符 返回类型 方法名(参数列表){......}
synchronized就是为当前的线程声明一把锁
代码演示如下:
* @Description模拟用户网络购票--使用同步方法解决线程带来的数据不安全问题
*/
public class TicketThread implements Runnable{
private int ticket=10;//记录车票总数
private int num=0;//记录用户抢到了几张票
private boolean flag=false;//代表票是否卖完
//用户抢票
public void run() {
while (true) {
sale();
}
}
public synchronized void sale(){
//没有余票,跳出循环
if (ticket<=0){
flag=true;
return;
}
//有余票,则抢票。第一步:修改车票数:总票数再抢完票后减一张,用户抢到票了,抢票数+1
ticket--;
num++;
//模拟网络延迟
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二步:显示出票反馈给用户
System.out.println(Thread.currentThread().getName()+"抢到了第"+num+"张票,剩余"+ticket+"张票");
}
public static void main(String[] args) {
Runnable runnable=new TicketThread();
Thread t1=new Thread(runnable,"淘票票");
Thread t2=new Thread(runnable,"快手张");
Thread t3=new Thread(runnable,"黄牛党");
System.out.println("*******各方开始抢票******");
t1.start();
t2.start();
t3.start();
}
}
使用synchronized关键字修饰的代码块
synchronized(syncObject){
//需要同步的代码
}
syncObject为需同步的对象,通常为this
效果与同步方法相同
代码演示
* @Description模拟用户网络购票--使用同步代码块解决线程带来的数据不安全问题
*/
public class TicketThread implements Runnable{
private int ticket=10;//记录车票总数
private int num=0;//记录用户抢到了几张票
private boolean flag=false;//代表票是否卖完
//用户抢票
public void run() {
while (true) {
synchronized (this) {
//没有余票,跳出循环
if (ticket <= 0) {
break;
}
//有余票,则抢票。第一步:修改车票数:总票数再抢完票后减一张,用户抢到票了,抢票数+1
ticket--;
num++;
//模拟网络延迟
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二步:显示出票反馈给用户
System.out.println(Thread.currentThread().getName() + "抢到了第" + num + "张票,剩余" + ticket + "张票");
}
}
}
public static void main(String[] args) {
Runnable runnable=new TicketThread();
Thread t1=new Thread(runnable,"淘票票");
Thread t2=new Thread(runnable,"快手张");
Thread t3=new Thread(runnable,"黄牛党");
System.out.println("*******各方开始抢票******");
t1.start();
t2.start();
t3.start();
}
}
多个并发线程访问同一资源的同步代码块时
同一个时刻只能有一个线程进入synchronized(this)同步代码块
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
当一个线程访问synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码
多线程共享数据:
可能带来的问题:数据不安全
原因:多线程共同操作数据时,引发的冲突(如延迟时,操作未全部完成等等)
思考:同步方法、同步代码块(synchronized)
线程同步:即各线程之间要有个先来后到,不能一窝蜂
线程同步其实是“排队”:上锁,排队,一个一个来,不能同时操作。
习题:
代码演示
* @Description模拟用户网络购票--使用同步代码块解决线程带来的数据不安全问题
*/
public class TicketThread implements Runnable{
private int ticket=10;//记录车票总数
private int num=0;//记录用户抢到了几张票
private boolean flag=false;//(1)代表票是否卖完(2)代表线程是否结束,flag:true,线程结束
//用户抢票
public void run() {
while (!flag) {
synchronized (this) {
//没有余票,跳出循环
if (ticket <= 0) {
break;
}
//有余票,则抢票。第一步:修改车票数:总票数再抢完票后减一张,用户抢到票了,抢票数+1
ticket--;
num++;
//模拟网络延迟
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二步:显示出票反馈给用户
System.out.println(Thread.currentThread().getName() + "抢到了第" + num + "张票,剩余" + ticket + "张票");
//判断当前线程名称是否为黄牛党,如果是线程结束,保证买一张票
if (Thread.currentThread().getName().equals("黄牛党")){
flag=true;
}else{
flag=false;
}
}
}
}
public static void main(String[] args) {
Runnable runnable=new TicketThread();
Thread t1=new Thread(runnable,"淘票票");
Thread t2=new Thread(runnable,"快手张");
Thread t3=new Thread(runnable,"黄牛党");
System.out.println("*******各方开始抢票******");
t1.start();
t2.start();
t3.start();
}
}
习题:
代码演示
public class RunThread implements Runnable {
//多个选手(多个线程)共同跑一千米
private int meters = 1000;
//实现一个选手拿到接力棒跑100米的过程
public void run() {
while (true) {
//同步代码块保证了在跑选手只有一人
synchronized (this) {
if (meters < 100) {
break;
}
//一个人拿到接力棒跑完100米
System.out.println(Thread.currentThread().getName() + "拿到了接力棒");
for (int i = 10; i <= 100; i += 10) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
}
//剩余的路途就减少一百米
meters -= 100;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//模拟几个选手参加接力赛
public static void main(String[] args) {
Runnable runnable=new RunThread();
Thread person1=new Thread(runnable,"选手赵");
Thread person2=new Thread(runnable,"选手钱");
Thread person3=new Thread(runnable,"选手孙");
Thread person4=new Thread(runnable,"选手李");
Thread person5=new Thread(runnable,"选手周");
person1.start();
person2.start();
person3.start();
person4.start();
person5.start();
}
}