java学习之线程2

  卖演唱会票例子

  保证:多个线程访问共享的数据(数据只有一份)

	public static void main(String[] args) {
		//创建3个线程
		TicketRunnable runnable=new TicketRunnable();
		Thread t1=new Thread(runnable);
		Thread t2=new Thread(runnable);
		Thread t3=new Thread(runnable);
		//开启线程
		t1.start();
		t2.start();
		t3.start();
	}

//接口实现线程的方式
class TicketRunnable implements Runnable{
	//声明票
	private int ticket=50;
	//声明锁对象
	private Object object=new Object();
	
	@Override
	public void run() {
		//循环卖
		while (true) {
			
			//同步锁
			synchronized (object) {
				//判断卖完没
				if (ticket>0) {
					//为了测试结果更明显加个线程休眠
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					//卖
					System.out.println(Thread.currentThread().getName()+"*****"+ticket);
					//卖一张 少一张
					ticket--;
				}else {
					//卖光了 结束循环
					break;
				}
			}
			//让出cpu的执行资源(随机让出)
			Thread.yield();
		}
	}
	
}

  同步代码块规则:

    当线程进入同步代码块的时候

    先看一下有没有锁

    如果有锁 就进入同步代码块中执行代码

    进去的同时会获取这把锁

    当代码执行完毕 出同步代码块时 将这把锁释放(还回去)

    如果没锁 线程在同步代码块前等待(等着有锁才能进)


    同步代码块(同步锁)

    锁:任意对象(只有一把锁 使用的是同一把锁)

    synchronized(锁){

   操作共享数据的代码

    }


  同步锁

    好处:数据安全

    坏处:效率会降低(获取锁和释放锁 会耗费资源)


  同步方法(作用和同步代码块相同)

    也是用synchronized关键字

    该关键字声明在方法上

    同一时间 只能有一个线程进入到同步方法中执行代码

    同步方法中 也是写操作共享数据的代码

    处理方式和同步代码块一样

public synchronized void sellTicket() {

}

  JDK1.5 Lock 接口

    使用实现类 ReentrantLock

    lock();获取锁

    unlock();释放锁(保证锁一定会被释放)

    使用前提:和同步代码块一样 要保证用的是同一把锁

    使用格式:

    try{

         操作共享数据的代码

    }finally{

     释放锁

    }

while (true) {
		//获取锁
		lock.lock();
		try {
				
		} finally {
		  lock.unlock();
		}
			
	}

  线程死锁

    前提:必须要有同步锁的嵌套

    2.锁对象要唯一(使用的是同一把锁)

    两把锁都要保证唯一

    synchronized(){

     synchronized(){

  

        }

    }

public static void main(String[] args) {
		//测试死锁
		DieLockRunnable runnable=new DieLockRunnable();
		Thread t1=new Thread(runnable);
		Thread t2=new Thread(runnable);
		t1.start();
		t2.start();
	}


//创建A锁
class LockA{
	//为了唯一 不让外人创建 自己创建
	private LockA(){
		
	}
	//定义一个常量
	public static final LockA LOCK_A=new LockA();
}
//创建B锁
class LockB{
	//为了唯一 不让外人创建 自己创建
	private LockB(){
		
	}
	//定义一个常量
	public static final LockB LOCK_B=new LockB();
}

class DieLockRunnable implements Runnable{
	//声明一个标记
	private boolean isFlag=true;
	//第一次 先进A锁再进B锁
	//下一次 先进B锁再进A锁
	
	@Override
	public void run() {
		//死循环 为了增加死锁的几率
		while (true) {
			if (isFlag) {
				//A->B
				synchronized (LockA.LOCK_A) {
					System.out.println("我是if的 LOCK_A锁");
					synchronized (LockB.LOCK_B) {
						System.out.println("我是if的 LOCK_B锁");
					}
				}
			}else {
				//B->A
				synchronized (LockB.LOCK_B) {
					System.out.println("我是else的LOCK_B锁");
					synchronized (LockA.LOCK_A) {
						System.out.println("我是else的 LOCK_A锁");
					}
				}
			}
			//修改标记
			isFlag=!isFlag;
		}
	}
	
}

  线程如何停止?

    interrupt()方法 中断线程

   1.调用interrupt方法是 线程中有wait()/sleep()等方法 这时会抛出一个异常

   interruptException异常 并且清除中断状态

   2.调用interrupt方法时 线程中没有上述方法

   这时会设置(改变)中断状态的值(true---false)

  public static void main(String[] args) {
		InterruptRunnable runnable=new InterruptRunnable();
		Thread t1=new Thread(runnable);
		t1.start();
		
		//给子线程几秒的执行时间 然后再中断线程
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//中断线程
		t1.interrupt();
		//标记中断线程
		runnable.isFlag=true;
		System.out.println("中断线程");
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("主线程结束");
	}


class InterruptRunnable implements Runnable{
	//声明一个标识 用来停止线程
	public boolean isFlag=false;

	@Override
	public void run() {
		//直接使用中断状态来中断线程
		while (!Thread.interrupted()) {
			//休眠
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			//休眠一秒(循环卡1秒)
			//long time = System.currentTimeMillis();
			//while (System.currentTimeMillis()-time<1000) {
				
			//}
					
			System.out.println(Thread.currentThread().getName()+"...run");
		}
	}
	
}

   调用interrupt方法时

    线程中有wait()方法

    wait()方法 线程等待并且如果没有被唤醒 就一直等待下去

    是Object类中的方法

    直接使用wait()方法会出现异常

    注意:wait()方法必须使用锁对象去调用

	public static void main(String[] args) {
		//创建两个线程 测试
		WaitRunnable runnable=new WaitRunnable();
		Thread t1=new Thread(runnable);
		Thread t2=new Thread(runnable);
		t1.start();
		t2.start();
		
		for (int i = 0; i < 50; i++) {
			if (i==25) {
				//调用interrupt方法测试
				t1.interrupt();
				t2.interrupt();
				//更改标记来中断线程
				runnable.isFlag=true;
			}
			System.out.println(i);
		}
		System.out.println("主线程结束");
	}


class WaitRunnable implements Runnable{

	//标记中断线程
	public boolean isFlag=false;
	@Override
	public synchronized void run() {
		while (!isFlag) {
			
			try {
				//线程等待
				//InterruptedException异常 抛出了
				//线程从等待状态变成运行状态
				//解除了等待状态
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			System.out.println(Thread.currentThread().getName()+"...run");
		}
	}
	
}

  从子线程中更改中断线程的标记

  让主线程能够接到这个标记改变

	public static void main(String[] args) {
		VolRunnable runnable=new VolRunnable();
		Thread t1=new Thread(runnable);
		t1.start();
		
		//利用中断状态卡住主线程
		while (!runnable.isFlag) {
			
		}
		System.out.println("主线程结束");
	}


class VolRunnable implements Runnable{
	//当子线程中修改状态 不能及时同步到主线程中
	//这时可以使用volatile关键词
	//让线程中的这个状态信息 可以及时得到修改

	//标记
	public volatile boolean isFlag=false;
	//声明一个变量 记录什么时候更改状态
	private int num=0;
	
	@Override
	public void run() {
		while (!isFlag) {
			num++;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if (num>5) {
				//更改中断状态
				isFlag=true;
			}
			System.out.println(Thread.currentThread().getName()+"...run");
		}
	}
	
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值