背景:.start()之后,线程并不是立即创建,线程也并非按顺序创建。若想让线程顺序创建,则需要了解线程间的通信,以及下一节线程间的定制化通信
线程间通信
线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模 型来实现的。我们来基本一道面试常见的题目来分析
对于之前的操作方法的编写可以进行细化,分为三步:判断、执行、通知
题目: 场景—-两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1,要求 用线程间通信 。让两个线程对同一变量进行操作,让其完成交替操作的效果
synchronized方案
package com.atguigu.test;
/**
* volatile 关键字实现线程交替加减
*/
public class TestVolatile {
/**
* 交替加减
* @param args
*/
public static void main( String[] args )
{
DemoClass demoClass = new DemoClass();
new Thread( () - > {
for ( int i = 0; i < 5; i++ )
{
demoClass.increment();
}
}, "线程 A" ).start();
new Thread( () - > {
for ( int i = 0; i < 5; i++ )
{
demoClass.decrement();
}
}, "线程 B" ).start();
}
}
package com.atguigu.test;
class DemoClass {
/* 加减对象 */
private int number = 0;
/**
* 加 1
*/
public synchronized void increment()
{
try {
while ( number != 0 ) //判断
{
this.wait();
}
number++; //工作
System.out.println( "--------" + Thread.currentThread().getName() + "加一成
功----------,值为:" + number );
notifyAll(); //通知
}catch ( Exception e ) {
e.printStackTrace();
}
}
/**
* 减一
*/
public synchronized void decrement()
{
try {
while ( number == 0 ) //判断
{
this.wait();
}
number--; //工作
System.out.println( "--------" + Thread.currentThread().getName() + "减一成
功----------,值为:" + number );
notifyAll(); //通知
}catch ( Exception e ) {
e.printStackTrace();
}
}
}
Lock方案
package com.atguigu.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class DemoClass {
/* 加减对象 */
private int number = 0;
/* 声明锁 */
private Lock lock = new ReentrantLock();
/* 声明钥匙 */
private Condition condition = lock.newCondition();
/**
* 加 1
*/
public void increment()
{
try {
lock.lock();
while ( number != 0 ) //判断
{
condition.await();
}
number++; /工作
System.out.println( "--------" + Thread.currentThread().getName() + "加一成
功----------,值为:" + number );
condition.signalAll(); //通知
}catch ( Exception e ) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 减一
*/
public void decrement()
{
try {
lock.lock();
while ( number == 0 )
{
condition.await();
}
number--;
System.out.println( "--------" + Thread.currentThread().getName() + "减一成
功----------,值为:" + number );
condition.signalAll();
}catch ( Exception e ) {
e.printStackTrace();
} finally {
lock.unlock()
}
}
}
wait()虚假判断
问题来源于wait()在哪里睡就会在哪里醒。当在判断和工作之间睡就会在此醒,这样就会让之前的判断失效,造成虚假判断。
所以把判断从if改为while,这样即使睡醒也要再参与判断,不会继续执行