1.实现生产者/消费者模式:一对一交替打印
创建项目4.1.7,类MyService.java,代码如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class MyService {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set(){
try{
lock.lock();
while (hasValue == true){
condition.await();
}
System.out.println("打印★");
hasValue = true;
condition.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void get(){
try {
lock.lock();
while (hasValue == false){
condition.await();
}
System.out.println("打印☆");
hasValue = false;
condition.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
线程类MyThreadA.java代码如下:
public class MyThreadA extends Thread{
private MyService service;
public MyThreadA(MyService service){
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
service.set();
}
}
}
线程类MyThreadB.java代码如下:
public class MyThreadB extends Thread{
private MyService service;
public MyThreadB(MyService service){
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
service.get();
}
}
}
运行类Run.java代码如下:
public class Run {
public static void main(String[] args) throws InterruptedException{
MyService service = new MyService();
MyThreadA a = new MyThreadA(service);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(service);
b.setName("B");
b.start();
}
}
运行结果如下所示:
打印☆
打印★
打印☆
打印★
打印☆
打印★
打印☆
打印★
打印☆
打印★
打印☆
打印★
打印☆
打印★
打印☆
打印★
由控制台运行结果可知,通过使用Condition对象,成功实现交替打印的效果。
2.实现生产者/消费者模式:多对多交替打印
创建项目4.1.8,类MyService.java代码如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class MyService {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set(){
try{
lock.lock();
while (hasValue == true){
System.out.println("有可能★★ 连续");
condition.await();
}
System.out.println("打印★");
hasValue = true;
condition.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void get(){
try {
lock.lock();
while (hasValue == false){
System.out.println("有可能☆☆ 连续");
condition.await();
}
System.out.println("打印☆");
hasValue = false;
condition.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
线程类MyThreadA.java代码如下:
public class MyThreadA extends Thread{
private MyService service;
public MyThreadA(MyService service){
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
service.set();
}
}
}
线程类MyThreadB.java代码如下:
public class MyThreadB extends Thread{
private MyService service;
public MyThreadB(MyService service){
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
service.get();
}
}
}
运行类Run.java代码如下:
public class Run {
public static void main(String[] args) throws InterruptedException{
MyService service = new MyService();
MyThreadA[] threadA = new MyThreadA[10];
MyThreadB[] threadB = new MyThreadB[10];
for (int i = 0; i < 10; i++) {
threadA[i] = new MyThreadA(service);
threadB[i] = new MyThreadB(service);
threadA[i].start();
threadB[i].start();
}
}
}
运行结果如下所示:
程序运行出现假死情况
打印★
有可能★★ 连续
打印☆
有可能☆☆ 连续
打印★
有可能★★ 连续
有可能★★ 连续
有可能★★ 连续
打印☆
有可能☆☆ 连续
有可能☆☆ 连续
打印★
有可能★★ 连续
有可能★★ 连续
有可能★★ 连续
打印☆
有可能☆☆ 连续
打印★
有可能★★ 连续
有可能★★ 连续
打印☆
有可能☆☆ 连续
有可能☆☆ 连续
这种情况可以使用siganlAll()方法来解决。将MyService.java类中的两处signal()代码给成siganlAll()后,程序得到正确运行,就会正确运行。从控制台输出,可以发现这样也解决了假死问题。
控制台中“打印★”和“打印☆”是交替输出的,但是“有可能★★连续”和“有可能☆☆连续”却不是交替输出的,有时候出现连续打印的情况。原因是程序中使用了一个Condition对象,再结合signalAll()方法来唤醒所有的线程,那么唤醒的线程就有可能是同类,所以就出现连续打印“有可能★★连续”或“有可能☆☆连续”的情况了。
3.公平锁与非公平锁
公平与非公平锁:锁Lock分为"公平锁"和"非公平锁",公平锁标识线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序,而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了。
创建java项目4.1.9,Service.java类,代码如下:
import java.util.concurrent.locks.ReentrantLock;
public class Service {
private ReentrantLock lock;
public Service(boolean isFair){
super();
lock = new ReentrantLock(isFair);
}
public void serviceMethod(){
try{
lock.lock();
System.out.println("ThreadName = "+Thread.currentThread().getName()+"获得锁定");
}finally {
lock.unlock();
}
}
}
创建公平锁运行类Run.java代码如下:
public class Run {
public static void main(String[] args) throws InterruptedException{
final Service service = new Service(true);
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("★线程"+Thread.currentThread().getName()+"运行了");
service.serviceMethod();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
}
}
程序运行结果如下所示:
★线程Thread-0运行了
★线程Thread-1运行了
ThreadName = Thread-0获得锁定
★线程Thread-5运行了
ThreadName = Thread-1获得锁定
ThreadName = Thread-5获得锁定
★线程Thread-6运行了
ThreadName = Thread-6获得锁定
★线程Thread-3运行了
ThreadName = Thread-3获得锁定
★线程Thread-4运行了
ThreadName = Thread-4获得锁定
★线程Thread-9运行了
ThreadName = Thread-9获得锁定
★线程Thread-7运行了
ThreadName = Thread-7获得锁定
★线程Thread-2运行了
ThreadName = Thread-2获得锁定
★线程Thread-8运行了
ThreadName = Thread-8获得锁定
打印的结果基本是呈有序状态,这就是公平锁的特点。
创建非公平锁运行类RunNotFair.java代码如下:
public class RunNotFair {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service(false);
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("★线程" + Thread.currentThread().getName() + "运行了");
service.serviceMethod();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(runnable);
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
}
}
程序运行结果如下所示:
★线程Thread-0运行了
★线程Thread-4运行了
★线程Thread-3运行了
★线程Thread-2运行了
★线程Thread-1运行了
★线程Thread-6运行了
★线程Thread-5运行了
ThreadName = Thread-0获得锁定
★线程Thread-7运行了
ThreadName = Thread-7获得锁定
★线程Thread-8运行了
ThreadName = Thread-8获得锁定
ThreadName = Thread-4获得锁定
★线程Thread-9运行了
ThreadName = Thread-9获得锁定
ThreadName = Thread-3获得锁定
ThreadName = Thread-2获得锁定
ThreadName = Thread-1获得锁定
ThreadName = Thread-6获得锁定
ThreadName = Thread-5获得锁定
非公平锁的运行结果基本上是乱序的,说明先start()启动的线程不代表先获得锁。
以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git