使用synchronized实现线程间通信,线程间通信:1、生产者+消费者2、通知等待唤醒机制.
多线程编程模板:1.判断 2.干活 3.通知
class ShareDataOne//资源类
{
private int number = 0;//初始值为零的一个变量
public synchronized void increment() throws InterruptedException
{
//1判断
if(number !=0 ) {
this.wait();
}
//2干活
++number;
System.out.println(Thread.currentThread().getName()+"\t"+number);
//3通知
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException
{
// 1判断
if (number == 0) {
this.wait();
}
// 2干活
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
// 3通知
this.notifyAll();
}
}
/**
*
* @Description:
*现在两个线程,
* 可以操作初始值为零的一个变量,
* 实现一个线程对该变量加1,一个线程对该变量减1,
* 交替,来10轮。
*
* * 笔记:Java里面如何进行工程级别的多线程编写
* 1 多线程变成模板(套路)-----上
* 1.1 线程 操作 资源类
* 1.2 高内聚 低耦合
* 2 多线程变成模板(套路)-----下
* 2.1 判断
* 2.2 干活
* 2.3 通知
*/
public class NotifyWaitDemoOne
{
public static void main(String[] args)
{
ShareDataOne sd = new ShareDataOne();
new Thread(() -> {
for (int i = 1; i < 10; i++) {
try {
sd.increment();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i < 10; i++) {
try {
sd.decrement();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "B").start();
}
}
换成4个线程会导致错误,虚假唤醒具体代码可以自己手敲,原因如下:
在java多线程判断时,不能用if,程序出事出在了判断上面,突然有一添加的线程进到if了,突然中断了交出控制权,没有进行验证,而是直接走下去了,加了两次,甚至多次.
所以为了防止虚假唤醒,解决虚假唤醒:查看API,java.lang.Object
中断和虚假唤醒是可能产生的,所以要用loop循环,if只判断一次 ,while是只要唤醒就要拉回来再判断一次。if换成while
改完之后代码如下
class ShareData//资源类
{
private int number = 0;//初始值为零的一个变量
public synchronized void increment() throws InterruptedException
{
//判断
while(number!=0) {
this.wait();
}
//干活
++number;
System.out.println(Thread.currentThread().getName()+" \t "+number);
//通知
this.notifyAll();;
}
public synchronized void decrement() throws InterruptedException
{
//判断
while(number!=1) {
this.wait();
}
//干活
--number;
System.out.println(Thread.currentThread().getName()+" \t "+number);
//通知
this.notifyAll();
}
}
public class NotifyWaitDemo
{
public static void main(String[] args)
{
ShareData sd = new ShareData();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
synchronized和LOCK换代后,wait换成了await,notify换成了 signalAll.
优化后的代码可以
package com.example.demo.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Shradata{
public int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment() throws Exception {
lock.lock();
try {
while (number != 0 ){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"\t"+number);
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void decrement() throws Exception {
lock.lock();
try {
while (number == 0 ){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"\t"+number);
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
/**
* @author xie
* @version 1.0
* @date 2020/6/27 9:05
*/
public class LockTest {
public static void main(String[] args) throws Exception{
Shradata shradata = new Shradata();
new Thread(()->{
for (int i = 1;i < 10;i++){
try {
shradata.increment();
} catch (Exception e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 1;i < 10;i++){
try {
shradata.decrement();
} catch (Exception e) {
e.printStackTrace();
}
}
},"B").start();
// new Thread(()->{
// for (int i = 1;i < 10;i++){
// shradata.decrement();
// }
// },"C").start();
// new Thread(()->{
// for (int i = 1;i < 10;i++){
// shradata.decrement();
// }
// },"D").start();
}
}
也可以定制化线程间得通信具体
1、有顺序通知,需要有标识位
2、有一个锁Lock,3把钥匙Condition
3、判断标志位
4、输出线程名+第几次+第几轮
5、修改标志位,通知下一个
代码实现:
package com.atguigu.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource
{
private int number = 1;//1:A 2:B 3:C
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5(int totalLoopNumber)
{
lock.lock();
try
{
//1 判断
while(number != 1)
{
//A 就要停止
c1.await();
}
//2 干活
for (int i = 1; i <=5; i++)
{
System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
}
//3 通知
number = 2;
c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10(int totalLoopNumber)
{
lock.lock();
try
{
//1 判断
while(number != 2)
{
//A 就要停止
c2.await();
}
//2 干活
for (int i = 1; i <=10; i++)
{
System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
}
//3 通知
number = 3;
c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15(int totalLoopNumber)
{
lock.lock();
try
{
//1 判断
while(number != 3)
{
//A 就要停止
c3.await();
}
//2 干活
for (int i = 1; i <=15; i++)
{
System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
}
//3 通知
number = 1;
c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
*
* @Description:
* 多线程之间按顺序调用,实现A->B->C
* 三个线程启动,要求如下:
*
* AA打印5次,BB打印10次,CC打印15次
* 接着
* AA打印5次,BB打印10次,CC打印15次
* ......来10轮
*
*/
public class ThreadOrderAccess
{
public static void main(String[] args)
{
ShareResource sr = new ShareResource();
new Thread(() -> {
for (int i = 1; i <=10; i++)
{
sr.print5(i);
}
}, "AA").start();
new Thread(() -> {
for (int i = 1; i <=10; i++)
{
sr.print10(i);
}
}, "BB").start();
new Thread(() -> {
for (int i = 1; i <=10; i++)
{
sr.print15(i);
}
}, "CC").start();
}
}
注:若有不足请指正.