买火车票的问题
主线程
三条分支线程
同步锁 同步代码块
对象锁的对象 可以是任意对象 但是要保证锁的唯一 多个线程 都要使用 同一把锁 但是只有一把钥匙
synchronized( 对象锁 ){
}
同步锁规则 : 如果没有锁需要在外面等待
如果有锁可以进去 携带锁进去
等出了代码块要把锁还回去
public class Test {
public static void main(String[] args) {
TitkesRunnable tRunnable = new TitkesRunnable();
//创建一个线程 这个线程会执行 run方法 (会执行这条线程的任务)
Thread t1 = new Thread(tRunnable);
Thread t2 = new Thread(tRunnable);
Thread t3 = new Thread(tRunnable);
//开启三个线程
t1.start();
t2.start();
t3.start();
}
}
class TitkesRunnable implements Runnable{
//声明50张票票 保证票是共享数据 只New一次该类对象
//同步锁可以解决
private int titkes = 50;
//创建了对象锁并且保证了锁的唯一性
private Object obj = new Object();
//卖票方法
@Override
/*
* 同步锁 同步代码块
* 对象锁的对象 可以是任意对象 但是要保证锁的唯一 多个线程 都要使用 同一把锁 但是只有一把钥匙
* synchronized( 对象锁 ){
*
* }
* @see java.lang.Runnable#run()
*/
public void run() {
// TODO Auto-generated method stub
while (true) {
//只要保证是对象 和 唯一的对象就可以 填this 可以
synchronized (obj) {
//操作的共有共享数据的代码
if (titkes>0) {
//在打印之前让线程休眠一会 增加线程访问的时间 扩大出问题的几率
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//有票就卖一张
System.out.println(Thread.currentThread().getName()+titkes);
//减少一场
titkes--;
}else {
//没票就不卖 结束循环
break;
}
}
//让线程放弃Cpu的资源
Thread.yield();
}
}
}
同步锁规则
同步锁规则
线程 遇到锁 就进 进代码块(并且携带锁)
当线程 执行完代码块中的代码 把锁返还
线程 没有遇到锁 会在同步代码块外等着 遇到锁才能进
静态方法的 同步代码块的锁 可以使用本类 类名.class
public class Test2 {
public static void main(String[] args) {
TitkesRunnable tRunnable = new TitkesRunnable();
//创建一个线程 这个线程会执行 run方法 (会执行这条线程的任务)
Thread t1 = new Thread(tRunnable);
Thread t2 = new Thread(tRunnable);
Thread t3 = new Thread(tRunnable);
//开启三个线程
t1.start();
t2.start();
t3.start();
}
}
class TitkesRunnable1 implements Runnable{
//声明50张票票 保证票是共享数据 只New一次该类对象
//同步锁可以解决
private int titkes = 50;
//创建了对象锁并且保证了锁的唯一性
private Object obj = new Object();
//卖票方法
@Override
/*
* 同步锁 同步代码块
* 对象锁的对象 可以是任意对象 但是要保证锁的唯一 多个线程 都要使用 同一把锁 但是只有一把钥匙
* synchronized( 对象锁 ){
*
* }
* @see java.lang.Runnable#run()
*/
public void run() {
while (true) {
if (sellTitkes()) {
break;
}
//让出cpu资源
Thread.yield();
}
}
//方法操作共享数据的方法
//在方法中添加 synchronized 关键字 把方法 变成 同步方法
//synchronized修饰的同步方法 一定有锁
public synchronized boolean sellTitkes() {
if (titkes>0) {
//在打印之前让线程休眠一会 增加线程访问的时间 扩大出问题的几率
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//有票就卖一张
System.out.println(Thread.currentThread().getName()+"---"+titkes);
//减少一场
titkes--;
//没卖完
return false;
}else {
//没票就不卖 结束循环
return true;
}
}
}
模拟线程死锁
1.需要两个锁对象(并且保证唯一)
public class Test3 {
public static void main(String[] args) {
DidLockRunnable didLockRunnable = new DidLockRunnable();
Thread LonkOne = new Thread(didLockRunnable);
Thread LonkTwo = new Thread(didLockRunnable);
LonkOne.start();
LonkTwo.start();
}
}
//第一个锁
class LonkOne{
//私有构造方法
private LonkOne() {
}
//定义一个常量 不能被修改也不能被创建
public static final LonkOne LONK_ONE = new LonkOne();
}
//第二个锁
class LonkTwo{
private LonkTwo() {
}
//定义一个常量 不能被修改也不能被创建
public static final LonkTwo LONK_TWO = new LonkTwo();
}
class DidLockRunnable implements Runnable{
//声明一个标记
//一次先走LonkOne 再走LonkTwo
//一次先走LonkTwo 再走LonkOne
public boolean isTrue = true;
@Override
public void run() {
//死循环(增加死锁率)
while (true) {
//按照标记走
if (isTrue) {
//让他走LonkOne --> LonkTwo
synchronized (LonkOne.LONK_ONE) {
System.out.println("is....LONK_ONE");
synchronized (LonkTwo.LONK_TWO) {
System.out.println("is....LONK_TWO");
}
}
//让他走LonkTwo --> LonkOne
}else {
synchronized (LonkTwo.LONK_TWO) {
System.out.println("is....LONK_TWO");
synchronized (LonkOne.LONK_ONE) {
System.out.println("is....LONK_ONE");
}
}
}
//修改标记
isTrue = !isTrue;
}
}
}
jdk 1.5 之后出现的锁
Lock
使用Lock锁
lock.lock();
try{
}finally{
lock.unlock();
}
接口实现 创建 线程的好处:
1. 避免了直接继承Thread类的局限性 (避免单继承)
2. 接口即插即用 减少 类与类之间的联系(可以解耦)
public class Test4 {
public static void main(String[] args) {
Titkets3 titkets3 = new Titkets3();
Thread s1Thread= new Thread(titkets3);
Thread s2Thread= new Thread(titkets3);
Thread s3Thread= new Thread(titkets3);
s1Thread.start();
s2Thread.start();
s3Thread.start();
}
}
class Titkets3 implements Runnable{
private int titkets = 50;
//声明所对象 声明成成员变量
private ReentrantLock Lock = new ReentrantLock();
public void run() {
while (true) {
Lock.lock();
try {
//要锁住操作共享数据的代码
if (titkets>0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--"+titkets);
titkets--;
}else {
break;
}
} finally {
// TODO: handle finally clause
//解锁
Lock.unlock();
}
//让出cpu资源
Thread.yield();
}
}
}