3、线程间通讯与线程间定制化通讯
2024/12/19大约 4 分钟
3、线程间通讯与线程间定制化通讯
1、线程间通讯
1、new Thread().start()方法介绍
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
//在此处调用了start0的方法
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
//该方法由native修饰,掉起操作系统执行线程,但是此时如果操作系统不繁忙,则会掉起该线程,如果操作系统繁忙,则会等会在执行该线程
private native void start0();
2、线程间通信
1、例子
定义一个初始值为0 ,假如有两个线程,线程a对初始值+1操作,线程b对初始值-1操作,依次执行线程a,线程b,即线程a执行一次,线程b执行一次,在线程a执行一次,在线程b执行一次......
下面的例子 aa/cc线程执行加法操作,bb/dd线程执行减法操作依次执行,但是aa/cc线程,或者bb/dd线程执行顺序不一定
package com.hjc.infor;
import java.util.concurrent.locks.ReentrantLock;
public class TestInfoSync {
public static void main(String[] args) {
A a = new A();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程aa").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程bb").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程cc").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程dd").start();
}
}
class A{
int a = 0;
private final ReentrantLock lock = new ReentrantLock();
public synchronized void add(){
if(a != 0){
//当前进入该线程的线程等待
this.wait();
}
a++;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
this.notifyAll();
}
public synchronized void del(){
if(a != 1){
//当前进入该线程的线程等待
this.wait();
}
a--;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
this.notifyAll();
}
}
2、虚假唤醒问题
上述例子存在虚假唤醒问题,this.wait()方法引发的问题,需要将if改成while
this.wait()在哪里睡就在哪里醒
1、案例解决 synchronized
package com.hjc.infor;
import java.util.concurrent.locks.ReentrantLock;
public class TestInfoSync {
public static void main(String[] args) {
A a = new A();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程aa").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程bb").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程cc").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程dd").start();
}
}
class A{
int a = 0;
private final ReentrantLock lock = new ReentrantLock();
public synchronized void add(){
while (a != 0){
//当前进入该线程的线程等待
this.wait();
}
a++;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
this.notifyAll();
}
public synchronized void del(){
while(a != 1){
//当前进入该线程的线程等待
this.wait();
}
a--;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
this.notifyAll();
}
}
2、案例解决 lock
private final ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //Condition中有await等待和signalAll/signal唤醒方法
package com.hjc.infor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestInfoSync {
public static void main(String[] args) {
A a = new A();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程aa").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程bb").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.add();
}
},"线程cc").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
a.del();
}
},"线程dd").start();
}
}
class A{
int a = 0;
private final ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//Condition中有await等待和signalAll/signal唤醒方法
public void add(){
lock.lock();
try {
while (a != 0){
//当前进入该线程的线程等待
condition.await();
}
a++;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
condition.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void del(){
lock.lock();
try {
while (a != 1){
//当前进入该线程的线程等待
condition.await();
}
a--;
System.out.println(Thread.currentThread().getName()+"-->"+a);
//唤醒当前进入该线程的线程
condition.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
3、解决方法
将线程等待方法写在while循环中,避免在哪里等待就在哪里唤醒,导致判断失效往后执行的问题
2、线程间的定制化通信
1、例子
启动三个线程,AA线程打印5此,BB线程打印10次,CC线程打印15次,进行10轮
package com.hjc.infor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestDingZhi {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(()->{
for (int i = 0; i < 10; i++) {
shareResource.print5(i);
}
},"aa").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
shareResource.print10(i);
}
},"bb").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
shareResource.print15(i);
}
},"cc").start();
}
}
class ShareResource{
private int flag = 1;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5(int time){
lock.lock();
try {
while ( flag!=1 ){
c1.await();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
}
flag = 2;
c2.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void print10(int time){
lock.lock();
try {
while ( flag!=2 ){
c2.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
}
flag = 3;
c3.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void print15(int time){
lock.lock();
try {
while ( flag!=3 ){
c3.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
}
flag = 1;
c1.signalAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}