1.创建线程的方法(这里不考虑继承Thread类)
通过实现Runnable接口的方式实现
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+"执行了....");}}
}public class Test01 {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);// 也可以直接写匿名类thread.start();for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+"执行了....");}}
}
2.同步代码块
同一个时间,只有一个线程可以运行,锁住
注意,必须是同一把锁,当然,由于基本数据类型的特殊性,有些基本数据类型也是可以锁住的,比如 Integer = (0-127) 之内是可以充当锁的,当然,锁只能锁住使用他的线程。
1.格式
synchronized(任意对象){
可能出现线程安全的代码
}
2.代码
public class Test {public static void main(String[] args) {Ticket ticket = new Ticket();Thread t1 = new Thread(ticket, "赵四");Thread t2 = new Thread(ticket, "广坤");Thread t3 = new Thread(ticket, "刘能");//开启线程t1.start();t2.start();t3.start();}
}
public class Ticket implements Runnable{int ticket = 100;//创建一个对象充当锁对象Object obj = new Object();@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj){if (ticket>0){System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");ticket--;}}}}
}
3.同步方法
1.介绍
关键字是synchrosnized 锁 this
所以,runnable的实现类要是同一个对象
或者使用static方法 这时候锁就是 类.class
2.代码块
public class Ticket implements Runnable {int ticket = 100;@Overridepublic void run() {while (true) {try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}method();}}/* public synchronized void method() {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");ticket--;}}*/public void method() {synchronized (this){if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");ticket--;}}}
}
4.关于对一个类的不同业务的思考
如果对一个类的不同业务处理,应该怎么处理呢?
线程如果对一个类进行操作,或者根据一个类的数据进行相应的方法调用?
首先第一点,必须要拿到这个类的数据,所以,必须要拿到这个类的对象,或者是这个类的子类。
- 将业务方法写在类中,然后通过类的对象进行调用
- 将业务方法写在线程类中,线程类中存一个类的对象。
1.包子铺代码
做一个卖一个
//包子铺代码 操作对象
public class BaoZiPu {//定义一个count证明生产包子,消费包子private int count;//定义一个flag,证明有没有包子private boolean flag;public BaoZiPu() {}public BaoZiPu(int count, boolean flag) {this.count = count;this.flag = flag;}//专门给消费线程服务public void getCount() {System.out.println("消费了第"+count+"个包子...........");}//专门给生产线程服务public void setCount() {count++;System.out.println("生产了第"+count+"个包子....");}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}}
// 实现类
public class Consumer implements Runnable{private BaoZiPu baoZiPu;public Consumer(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (baoZiPu){//如果flag等于false.证明没有包子,消费线程等待if (baoZiPu.isFlag() == false){try {baoZiPu.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为true,证明有包子,消费包子,然后唤醒生活线程baoZiPu.getCount();//改变flag状态为false,证明没有包子了baoZiPu.setFlag(false);//唤醒生产线程baoZiPu.notify();}}}
}
public class Product implements Runnable{private BaoZiPu baoZiPu;public Product(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (baoZiPu){//如果flag等于true.证明有包子,生产线程等待if (baoZiPu.isFlag() == true){try {baoZiPu.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为false,证明没有包子,生产包子,然后唤醒消费线程baoZiPu.setCount();//改变flag状态为true,证明有包子了baoZiPu.setFlag(true);//唤醒消费线程baoZiPu.notify();}}}
}
public static void main(String[] args) throws Exception{BaoZiPu baoZiPu = new BaoZiPu();Thread t1 = new Thread(new Product(baoZiPu));Thread t2 = new Thread(new Consumer(baoZiPu));t1.start();t2.start();}
问题:
1.为什么wait不能放在最后执行
while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (baoZiPu){//如果flag等于true.证明有包子,生产线程等待if (baoZiPu.isFlag() == true){//如果flag为false,证明没有包子,生产包子,然后唤醒消费线程baoZiPu.setCount();//改变flag状态为true,证明有包子了baoZiPu.setFlag(true);//唤醒消费线程baoZiPu.notify();try {baoZiPu.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}
因为notify是将线程唤醒,线程是跟着wait继续走的,这时候直接循环,但是,如果拿到锁却拿不到条件,直接卡死在这里了
2.多生产多消费的包子铺
notifyAll 但是这样还是消耗资源比较严重,因为有可能出现多次重复拿到锁但是无法运行放弃锁,并且有些拿不到锁的也唤醒了.
public class BaoZiPu {//定义一个count证明生产包子,消费包子private int count;//定义一个flag,证明有没有包子private boolean flag;public BaoZiPu() {}public BaoZiPu(int count, boolean flag) {this.count = count;this.flag = flag;}//专门给消费线程服务public synchronized void getCount() {//如果flag等于false.证明没有包子,消费线程等待while (flag == false) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为true,证明有包子,消费包子,然后唤醒生活线程System.out.println("消费了第" + count + "个包子...........");//改变flag状态为false,证明没有包子了flag = false;//唤醒生产线程this.notifyAll();}//专门给生产线程服务public synchronized void setCount() {//如果flag等于true.证明有包子,生产线程等待while (flag == true) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为false,证明没有包子,生产包子,然后唤醒消费线程count++;System.out.println("生产了第" + count + "个包子....");//改变flag状态为true,证明有包子了flag = true;//唤醒消费线程this.notifyAll();}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}
}
public class Consumer implements Runnable{private BaoZiPu baoZiPu;public Consumer(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}baoZiPu.getCount();}}
}
public class Product implements Runnable{private BaoZiPu baoZiPu;public Product(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}baoZiPu.setCount();}}
}
public class Test01 {public static void main(String[] args) {//创建包子铺对象BaoZiPu baoZiPu = new BaoZiPu();Product product = new Product(baoZiPu);Consumer consumer = new Consumer(baoZiPu);//两个生产线程new Thread(product).start();new Thread(product).start();//两个消费线程new Thread(consumer).start();new Thread(consumer).start();}
}
5.Lock
1. 介绍
Lock lock = new ReentrantLock();lock.lock();// 加锁lock.unlock(); // 解锁
6.condition阻塞队列
void await() ->线程等待 // 让当前线程等等void signal()->线程唤醒 // 从队列中唤醒一个等待线程Condition condition = lock.newCondition();
可以分业务唤醒队列,一个队列一个业务
1.包子例题
public class BaoZiPu {//定义一个count证明生产包子,消费包子private int count;//定义一个flag,证明有没有包子private boolean flag;//创建Lock对象Lock lock = new ReentrantLock();//为生产者创建Condition对象Condition productCondition = lock.newCondition();//为消费者创建Condition对象Condition consumerCondition = lock.newCondition();public BaoZiPu() {}public BaoZiPu(int count, boolean flag) {this.count = count;this.flag = flag;}//专门给消费线程服务public void getCount() {//获取锁lock.lock();//如果flag等于false.证明没有包子,消费线程等待while (flag == false) {try {//消费线程等待consumerCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为true,证明有包子,消费包子,然后唤醒生活线程System.out.println("消费了第" + count + "个包子...........");//改变flag状态为false,证明没有包子了flag = false;//唤醒生产线程productCondition.signal();//释放锁lock.unlock();}//专门给生产线程服务public void setCount() {//获取锁lock.lock();//如果flag等于true.证明有包子,生产线程等待while (flag == true) {try {//生产线程等待productCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}//如果flag为false,证明没有包子,生产包子,然后唤醒消费线程count++;System.out.println("生产了第" + count + "个包子....");//改变flag状态为true,证明有包子了flag = true;//唤醒消费线程consumerCondition.signal();//释放锁lock.unlock();}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}
}
public class Consumer implements Runnable{private BaoZiPu baoZiPu;public Consumer(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}baoZiPu.getCount();}}
}
public class Product implements Runnable{private BaoZiPu baoZiPu;public Product(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}baoZiPu.setCount();}}
}
public class Test01 {public static void main(String[] args) {//创建包子铺对象BaoZiPu baoZiPu = new BaoZiPu();Product product = new Product(baoZiPu);Consumer consumer = new Consumer(baoZiPu);//两个生产线程new Thread(product).start();new Thread(product).start();//两个消费线程new Thread(consumer).start();new Thread(consumer).start();}
}