java线程同步

买票案例

1、定义一个类TicketThread实现Runnable接口,里面定义一个成员变量:private int tickets = 100
2、在该类中重写run()方法实现买票
3、判断票大于0,就卖票,并告知是哪个窗口卖的
4、卖了票,总票数要减1
5、如果没了,线程终止
6、定义一个测试类
7、创建该类的对象
8、创建三个Thread类的对象,把TicketThread对象作为构造方法的参数,并给出对应的窗口名称
9、启动线程
//TicketThread类
public class TicketThread implements Runnable{

    private int ticket = 100;

    private static Object obj = new Object();

    @Override
    public void run() {

        while (true){

               if(ticket <= 0){

                   break;

               }else {

                   try {
                       Thread.sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

                   System.out.println(Thread.currentThread().getName()+" 在卖票"+" 剩余 "+ticket张");

                   ticket--;

              }
        }
    }
}

//main方法
public class TicketMain {

    public static void main(String[] args) {

        TicketThread tt = new TicketThread();

        Thread t1 = new Thread(tt,"t1");
        Thread t2 = new Thread(tt,"t2");
        Thread t3 = new Thread(tt,"t3");

        t1.start();
        t2.start();
        t3.start();

    }
}

问题

1、相同票出现了多次 2、出现了负数的票

原因

线程执行的随机性导致的,可能在卖票过程中丢失cpu的执行权,导致出现问题

解决

问题出现的条件
1、是多线程环境
2、有共享数据
3、有多条语句操作共享数据

怎么实现
1、把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行

2、java提供了同步代码块的方式来解决

同步代码块格式:

synchronized(任意对象) {
多条语句操作共享数据的代码
}

synchronized(任意对象):任意对象就可以看成就是一把锁

同步代码块的好处和弊端
好处:解决了多线程的数据安全问题
弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的 运行效率

代码示例

public class SellTicket implements Runnable{

	private int ticket = 100;
	private Object obj = new Object();

	@Override
	public void run(){
	
		while(true){
		
			synchronized(obj){
			
               if(ticket <= 0){

                   break;

               }else {

                   try {
                       Thread.sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }

                   System.out.println(Thread.currentThread().getName()+" 在卖票"+" 剩余 "+ticket张");

                   ticket--;

              }
           }
		}
	}
}

public static void main(String[] args){
	SellTicket st = new SellTicket();

	Thread t1 = new Thread(st,t1);
	Thread t2 = new Thread(st,t2);
	Thread t3 = new Thread(st,t3);

	t1.start();
	t2.start();
	t3.start();

}

同步方法解决数据安全问题
格式

修饰符 synchronized 返回值类型 方法名(方法参数){方法体}

注意:
1、同步方法的锁对象是this
2、静态同步方法的锁对象是字节码文件

代码示例

public class SellTicket implements Runnable{

	private int ticket = 100;

	public synchronized void sell(){

		@Override
		public void run(){
	
			while(true){
		
				synchronized(SellTicket.class){
			
               		if(ticket <= 0){

                   		break;

               		}else {

                   		try {
                       		Thread.sleep(100);
                   		} catch (InterruptedException e) {
                       		e.printStackTrace();
                   		}

                   		System.out.println(Thread.currentThread().getName()+" 在卖票"+" 剩余 "+ticket张");

                   		ticket--;

              		}
           		}
			}
		}
	}
}

Lock锁

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

ReentrantLock构造方法

方法名说明
ReentrantLock()创建一个ReentrantLock的实例

加锁解锁方法

方法名
void lock()获得锁
void unlock()释放锁

代码示例

public class SellTicket implements Runnable{

	private ReentrantLock lock = new ReentrantLock();

	private int ticket = 100;

		@Override
		public void run(){
	
			while(true){
	
				try{
					lock.lock();
					if(ticket <= 0){
						break;
					}else{
						Thread.sleep();
						ticket--;
						System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
					}
				}catch(InterruptedException e){
					e.printStackTrace();
				}finally{
					lock.unlock();
				}
			}
		}
	}
}

注意:tryLock会去尝试获取锁对象,如果获取到,则进行,否则,去做其他事

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值