1、需求
- 现在两个线程
- 操作一个初始值为0的变量
- 实现一个线程对变量增加1,一个线程对变量减少1
- 交替,来10轮
2、多线程编程模板中
1)判断
2)干活
3)通知
线程间通信:
1.生产者+消费者
2.通知等待唤醒机制
3、synchronized实现两个线程
class ShareDataOne{
private int number=0;
public synchronized void incre() throws InterruptedException {
//判断
if(number!=0){
this.wait();
}
//干活
++number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
this.notifyAll();
}
public synchronized void decre() throws InterruptedException {
//判断
if(number!=1){
this.wait();
}
//干活
--number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
this.notifyAll();
}
}
/**
* 现在两个线程
* 操作一个初始值为0的变量
* 实现一个线程对变量增加1,一个线程对变量减少1
* 交替,来10轮
*1、线程 操作 资源类
* 2、高内聚低耦合
* 1、判断
* 2、干活
* 3、通知
*
*/
public class NotifyWaitDemo {
public static void main(String[] args) {
ShareDataOne shareDataOne = new ShareDataOne();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.incre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.decre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
}
}
4、 synchronized实现四个线程
(1)换成4个线程会导致错误,虚假唤醒
原因:在java多线程判断时,不能用if,程序出事出在了判断上面,
突然有一添加的线程进到if了,突然中断了交出控制权,
没有进行验证,而是直接走下去了,加了两次,甚至多次。
(2)解决办法
解决虚假唤醒:查看API,java.lang.Object
中断和虚假唤醒是可能产生的,所以要用loop循环,if只判断一次,while是只要唤醒就要拉回来再判断一次。if换成while
5、多线程编程模板下
注意多线程之间的虚假唤醒
6、正确代码
class ShareDataOne{
private int number=0;
public synchronized void incre() throws InterruptedException {
//判断
while(number!=0){
this.wait();
}
//干活
++number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
this.notifyAll();
}
public synchronized void decre() throws InterruptedException {
//判断
while(number!=1){
this.wait();
}
//干活
--number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
this.notifyAll();
}
}
/**
* 现在两个线程
* 操作一个初始值为0的变量
* 实现一个线程对变量增加1,一个线程对变量减少1
* 交替,来10轮
*1、线程 操作 资源类
* 2、高内聚低耦合
* 1、判断
* 2、干活
* 3、通知
*
*/
public class NotifyWaitDemo {
public static void main(String[] args) {
ShareDataOne shareDataOne = new ShareDataOne();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.incre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.decre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.incre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
shareDataOne.decre();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}
7、lock实现线程间通信
Condition:查看API,java.util.concurrent
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
8、lock版代码
class ShareDataOne{
private int number=0;
private Lock lock = new ReentrantLock();
private Condition cd = lock.newCondition();
public void incre() throws InterruptedException {
lock.lock();
try {
//判断
while(number!=0){
cd.await();
}
//干活
++number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
cd.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decre() throws InterruptedException {
lock.lock();
try {
//判断
while(number!=1){
cd.await();
}
//干活
--number;
System.out.println(Thread.currentThread().getName()+
"\t"+number);
//通知
cd.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}