多线程编程
多线程编程思路
1、采用多线程操作资源类,满足高类聚,低耦合的思想。所有的操作封装成方法,在主线程中创建线程并直接调用其方法。
2、在资源类中编写供线程调用的方法步骤为:
- 判断
先判断,当前线程是否满足条件执行。并且注意避免虚假唤醒。
while(!condition){
condition.await();
}
- 执行
执行当前线程的逻辑代码 - 唤醒其他线程
condition.signalAll();
题目
一个初始值为0的变量,两个线程交替对其加一减一,执行五次。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
/**
* 资源类,资源类里有对应的锁对象,在主线程中只需要调用其方法
*/
class Resource {
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increase() {
lock.lock();
try {
while (num != 0) {
condition.await();
}
num++;
System.out.printf("%s\tnum = %d%n", Thread.currentThread().getName(), num);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrease() {
lock.lock();
try {
while (num == 0) {
condition.await();
}
num--;
System.out.printf("%s\tnum = %d%n", Thread.currentThread().getName(), num);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Main {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(() -> {
IntStream.range(0, 5).forEach(i -> {
resource.increase();
});
}, "A").start();
new Thread(() -> {
IntStream.range(0, 5).forEach(i -> {
resource.decrease();
});
}, "B").start();
}
}
A num = 1
B num = 0
A num = 1
B num = 0
A num = 1
B num = 0
A num = 1
B num = 0
A num = 1
B num = 0
三个线程交替打印ABC
最好的方式是采用三个condition,使用signal方法实现精确唤醒,并使用状态值切换状态。推荐使用这种方式。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
class Resource {
private int num = 1;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void printA() {
lock.lock();
try {
while (num != 1) {
c1.await();
}
System.out.println("A");
num = 2;
c2.signal();//唤醒printB的线程
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (num != 2) {
c2.await();
}
System.out.println("B");
num = 3;
c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (num != 3) {
c3.await();
}
System.out.println("C");
num = 1;
c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Main {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{
IntStream.range(0,10).forEach(i->{
resource.printA();
});
}).start();new Thread(()->{
IntStream.range(0,10).forEach(i->{
resource.printB();
});
}).start();
new Thread(() -> {
IntStream.range(0, 10).forEach(i -> {
resource.printC();
});
}).start();
}
}
采用一个condition也可以,关键还是状态值的切换。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
class Resource {
private int num = 1;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void printA() {
lock.lock();
try {
while (num != 1) {
condition.await();
}
System.out.println("A");
num = 2;
condition.signalAll();//唤醒printB的线程
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (num != 2) {
condition.await();
}
System.out.println("B");
num = 3;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (num != 3) {
condition.await();
}
System.out.println("C");
num = 1;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Main {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(() -> {
IntStream.range(0, 10).forEach(i -> {
resource.printA();
});
}).start();
new Thread(() -> {
IntStream.range(0, 10).forEach(i -> {
resource.printB();
});
}).start();
new Thread(() -> {
IntStream.range(0, 10).forEach(i -> {
resource.printC();
});
}).start();
}
}