您的位置:首页 > 编程语言 > Java开发

java多线程:线程的通信、唤醒等待机制、生产消费者模式、Lock

2018-09-19 19:34 603 查看

线程的通信:打印机打印–不断的输入输出

package com.qianfeng.test;
/*
* 线程的通信:
* 分析:
* 需要两个线程--输入线程和输出线程
* 需要两个任务--输入任务和输出任务
* 需要一份数据
*
* 实现:打印机打印--不断的输入不断的输出
*
*/
public class Demo2 {

public static void main(String[] args) {

//1.创建数据类对象
Des des =new Des();
//创建任务类对象并绑定数据
Input input = new Input(des);
Output output = new Output(des);
//3.创建线程
Thread inputThread = new Thread(input);
Thread outputThread = new Thread(output);
//4.开启线程
inputThread.start();
outputThread.start();

}
}

//创建数据类
class Des{
String name;
String sex;
}

//创建输入任务
class Input implements Runnable{

Des des;
public Input(Des des){
this.des=des;
}

public void run() {
/*
* 分析:需要输入任务与输出任务共用一把锁,保证两个任务之间是同步的。
* 给两个任务加一把锁,锁可以是des或Object.class
*
* 不建议使用Object.class,因为Object.class应用范围太大,其它地方可能也会用到。
* 使用des最合适,因为它只被两个线程共享。
*
* 注意:只给一个任务加锁无法实现两个线程的同步。
*/
int i = 0;
while(true){
synchronized (des) {
if (i==1) {
des.name = "凤姐";
des.sex = "男" ;
}else {
des.name = "芙蓉姐姐";
des.sex = "女" ;
}
i=(i+1)%2;
}
}
}
}

//创建输出任务
class Output implements Runnable{

Des des;
public Output(Des des){
this.des=des;
}

public void run() {
while(true){
synchronized (des) {
System.out.println("姓名:"+des.name+"  性别"+des.sex);
}
}
}
}

唤醒等待机制,wait()/notify()/notifyAll()

package com.qianfeng.test;

/*
* 线程的通信:
* 分析:
* 需要两个线程--输入线程和输出线程
* 需要两个任务--输入任务和输出任务
* 需要一份数据
*
* 实现:打印机打印--一次输入一次输出
*
* 使用唤醒等待机制实现:wait()/notify()/notifyAll()等
* wait():让当前的线程进入等待的状态,他会被放入一个池子(线程池),失去了抢cpu的能力,等待唤醒。(锁--相当于给当前线程做了一个标记)
* notify():让当前的线程从等待线程唤醒,相当于从池子中取出线程。(唤醒的是同一把锁下的任意一个线程)
* notifyAll():唤醒的是同一把锁下的所有线程。
*/
public class Demo3 {

public static void main(String[] args) {

// 1.创建数据类对象
Des1 des = new Des1();
// 创建任务类对象并绑定数据
Input1 input = new Input1(des);
Output1 output = new Output1(des);
// 3.创建线程
Thread inputThread = new Thread(input);
Thread outputThread = new Thread(output);
// 4.开启线程
inputThread.start();
outputThread.start();

}
}

// 创建数据类
// 封装类的原则:是你的活你做,不是你的活不要做。
class Des1 {
String name;
String sex;
boolean flag = false;// 创建一个标识,控制唤醒与等待的切换。

// 获取数据--处理输入
public synchronized void setData(String name, String sex) {
if (flag == true) {
try {// 让输入线程等待,当flag值为true的时候
// 在执行代码的时候,这里对应的是哪个线程,锁对象操作的就是哪个线程。
wait();// 只要一执行wait,线程会立刻停在这里,等待下次唤醒。
} catch (InterruptedException e) {
e.printStackTrace();
}
}

this.name = name;
this.sex = sex;

flag = !flag;
//// 唤醒输出线程。
// 当执行唤醒的时候,在线程池中没有找到被当前的锁标记的线程,我们称为空唤醒,空唤醒对程序没有影响,程序允许空唤醒。
notify();

}

// 将数据打印到控制台--处理输出
public synchronized void getData() {
if (flag == false) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("姓名:" + name + "  性别" + sex);
flag = !flag;
notify();
}

}

// 创建输入任务
class Input1 implements Runnable {

Des1 des;
public Input1(Des1 des) {
this.des = des;
}

public void run() {

int i = 0;
while (true) {
if (i == 1) {
des.setData("凤姐", "男");
} else {
des.setData("芙蓉姐姐", "女");
}
i = (i + 1) % 2;
}
}
}

// 创建输出任务
class Output1 implements Runnable {

Des1 des;
public Output1(Des1 des) {
this.des = des;
}

public void run() {
while(true){
des.getData();
}

}
}

多线程设计模式:单生产者单消费者

package com.qianfeng.test;
/*
* 多线程的设计模式:生产者消费者
* 两类:
* 1.单生产者单消费者
* 2.多生产者多消费者
*
* 先研究单生产者单消费者
* 分析:
* 生产线程,消费线程
* 生产任务,消费任务
* 产品
*/
public class Demo4 {
public static void main(String[] args) {
//1.创建产品
Product product = new Product();
//2.创建生产任务,消费任务
Producer producer = new Producer(product);
Consumer consumer = new Consumer(product);

//3.创建生产线程,消费线程
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);

//4.开启线程
t1.start();
t2.start();
}
}

//创建产品类
class Product{
String name;
double price;
int count;

boolean flag = false;//用来在唤醒与等待之间进行切换

//为生产准备数据
public synchronized void setProduce(String name,double price){
if (flag == true) {
try {
wait();//让生产线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}

this.name = name;
this.price = price;

System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
count++;

flag = ! flag;
notify();//唤醒消费线程
}
//为消费准备数据
public  synchronized void consume() {
if (flag == false) {
try {
wait();//让消费线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}

System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);

flag = ! flag;
notify();//唤醒生产线程
}
}

//创建生产任务
class Producer implements Runnable{
Product product;
public Producer(Product product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.setProduce("bingbing", 10);
}
}
}
//创建消费任务
class Consumer implements Runnable{
Product product;
public Consumer(Product product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}

多线程设计模式:多生产者多消费者

package com.qianfeng.test;
/*
* 多线程的设计模式:生产者消费者
* 两类:
* 1.单生产者单消费者
* 2.多生产者多消费者
*
* 研究多生产者多消费者
* 分析:
* 生产线程,消费线程有多个
* 生产任务,消费任务各有一个
* 产品一个
*/
public class Demo5 {
public static void main(String[] args) {
//1.创建产品
Product1 product = new Product1();
//2.创建生产任务,消费任务
Producer1 producer = new Producer1(product);
Consumer1 consumer = new Consumer1(product);

//3.创建生产线程,消费线程
Thread t0 = new Thread(producer);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
Thread t3 = new Thread(consumer);

//4.开启线程
t0.start();
t1.start();
t2.start();
t3.start();

}
}

//创建产品类
class Product1{
String name;
double price;
int count;

boolean flag = false;//用来在唤醒与等待之间进行切换

//为生产准备数据
public synchronized void setProduce(String name,double price){
while (flag == true) {
try {
wait();//让生产线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}

this.name = name;
this.price = price;

System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
count++;

flag = ! flag;
//notify();//唤醒消费线程
notifyAll();
}
//为消费准备数据
public  synchronized void consume() {
while (flag == false) {
try {
wait();//让消费线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}

System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);

flag = ! flag;
//notify();//唤醒生产线程
notifyAll();
}
}

//创建生产任务
class Producer1 implements Runnable{
Product1 product;
public Producer1(Product1 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.setProduce("bingbing", 10);
}
}
}
//创建消费任务
class Consumer1 implements Runnable{
Product1 product;
public Consumer1(Product1 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}

Lock,Condition。Lock与synchronized的比较

package com.qianfeng.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
* Lock:
* 比较synchronized和Lock
* 1.synchronized:从jdk1.0开始使用----隐式同步
* 	synchronized(锁对象){//获取锁   我们将这里的锁称为锁旗舰或者监听器
* 		同步的代码
* }//释放锁
* 2.Lock:从jdk1.5开始使用----显示同步
* 原理:Lock是接口,我们要通过他的子类工作
* 具体的工作流程:
* 	首先调用lock的lock()方法,获取锁
*      进行同步操作的代码
*  调用lock的unlock()方法,释放锁
*
*  使用场景总结:
*  1.当进行多生产者的消费者的时候,使用lock,其他的使用synchronized
*
*  使用效率上lock比synchronized高.
*/

public class Demo6 {
public static void main(String[] args) {
//1.创建产品
Product2 product = new Product2();
//2.创建生产任务,消费任务
Producer2 producer = new Producer2(product);
Consumer2 consumer = new Consumer2(product);

//3.创建生产线程,消费线程
Thread t0 = new Thread(producer);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
Thread t3 = new Thread(consumer);

//4.开启线程
t0.start();
t1.start();
t2.start();
t3.start();

}
}

//创建产品类
class Product2{
String name;
double price;
int count;

boolean flag = false;//用来在唤醒与等待之间进行切换

//创建Lock的对象
Lock lock = new ReentrantLock();

//创建用于生产线程的Condition对象
Condition proCon = lock.newCondition();
//创建用于消费线程的Condition对象
Condition conCon = lock.newCondition();

//为生产准备数据
public  void setProduce(String name,double price){
try {
lock.lock();//获取锁
while (flag == true) {
try {
//wait();//让生产线程等待
proCon.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

this.name = name;
this.price = price;

System.out.println(Thread.currentThread().getName()+"  生产了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);
count++;

flag = ! flag;
//notify();//唤醒消费线程
//notifyAll();
conCon.signal();

} finally {//必须执行的代码
lock.unlock();//释放锁
}

}
//为消费准备数据
public   void consume() {
try {
lock.lock();
while (flag == false) {
try {
//wait();//让消费线程等待
conCon.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

System.out.println(Thread.currentThread().getName()+"  消费了:"+name+"  产品的数量:"+count+"  产品的价格:"+price);

flag = ! flag;
//notify();//唤醒生产线程
//notifyAll();
proCon.signal();
} finally {
lock.unlock();
}

}
}

//创建生产任务
class Producer2 implements Runnable{
Product2 product;
public Producer2(Product2 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.setProduce("bingbing", 10);
}
}
}
//创建消费任务
class Consumer2 implements Runnable{
Product2 product;
public Consumer2(Product2 product) {
super();
this.product = product;
}
public void run() {
while (true) {
product.consume();
}
}
}

守护线程,setDaemon。

package com.qianfeng.test;
/*
* 守护线程:相当于后台线程,依赖于前台线程。正常情况下,当前台线程结束的时候,不管后台线程有没有结束,都会立即结束。
* 典型的守护线程:垃圾回收线程。
*
*/
public class Demo7 {

public static void main(String[] args) {

Test test = new Test();
Thread thread = new Thread(test);
/*
* 当程序调用setDaemon的时候,并且将参数设置为true,他就变成了守护线程。
* 注意:这个方法一定要在start方法之前调用。
*/
thread.setDaemon(true);
thread.start();

int i = 0;
while(true){
if (i++ == 10 ) {
System.out.println(Thread.currentThread().getName()+" i"+i);
break;//主线程结束
}
}
}
}

class Test implements Runnable{

public void run() {
while(true){
System.out.println("守护线程");
}

}
}

join方法

package com.qianfeng.test;
/*
* join()方法:
* 原理:程序一旦调用了join方法,他的优先级会高于主线程。意思是说,主线程会等当前线程执行完后再去执行。
* 注意:这个线程的优先级只比main高,对其它的线程没有影响。
*
*/
public class Demo8 {

public static void main(String[] args) {

Dog dog = new Dog();
Thread thread0 = new Thread(dog);
Thread thread1 = new Thread(dog);
thread0.start();
thread1.start();

/*
* 当线程开始工作后,让thread0调用join()方法,它的优先级会高于main线程。
* 注意:join()方法必须在线程开始工作后执行
*/
try {
thread0.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" i"+i);
}

}
}

class Dog implements Runnable{

public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" i"+i);
}

}

}
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐