Java多线程的实现方式二
Lock(锁)
从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和
内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁
实现
import java.util.concurrent.locks.ReentrantLock;
class Window implements Runnable{
private int tic = 10;
//实例化lock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//调用lock锁定方法
lock.lock();
if (tic>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":飘号"+":"+tic);
tic--;
}else {
break;
}
}finally {
//3.调用解锁方法
lock.unlock();
}
}
}
}
public class LookTest {
public static void main(String[] args) {
Window w = new Window();
Thread t1= new Thread(w);
Thread t2= new Thread(w);
Thread t3= new Thread(w);
t1.start();
t2.start();
t3.start();
}
}
测试结果
Thread-0:飘号:10
Thread-0:飘号:9
Thread-0:飘号:8
Thread-0:飘号:7
Thread-1:飘号:6
Thread-1:飘号:5
Thread-1:飘号:4
Thread-1:飘号:3
Thread-2:飘号:2
Thread-2:飘号:1
Process finished with exit code 0
synchronized 与lock的
形同点解决线程安全问题
不同点:synchronized机制在执行完相应的代码块以后,自动的释放同步监视器
lock需要手动的启动同步,同时结束也需要手动释放监视器
线程通信问题
/**
* 线程通信的例子
* wait():一旦线程执行此方法进入阻塞状态,并且释放锁
* notify(): 一旦执行此方法,就会和唤醒wait的线程,如果多个线程wait,就唤醒优先及高的线程
* notifyAll():一旦执行此方法,就会唤醒所以被wait的线程
*说明:1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块,或同步方法中。
* 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器;
* 否则java.lang.IllegalMonitorStateException
*
*/
class Number implements Runnable{
private int number=1;
private Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj) {
obj.notify();
if (number<=10){
System.out.println(Thread.currentThread().getName()+":"+number);
number++;
try {
//使得调用此wait()方法的线程进入阻塞状态,并会释放锁
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
public class CommunicationTest {
public static void main(String[] args) {
Number n1 = new Number();
Thread thread1 = new Thread(n1);
Thread thread2 = new Thread(n1);
thread1.setName("线程1");
thread2.setName("线程2");
thread1.start();
thread2.start();
// System.out.println();
}
}
测试结果
线程1:1
线程2:2
线程1:3
线程2:4
线程1:5
线程2:6
线程1:7
线程2:8
线程1:9
线程2:10
Process finished with exit code 0
sleep()和wait()方法
相同点:线程执行到它们的时候进入阻塞状态
不同点:两个方法声明的位置不同;Thread类中声明seelp(),Object中声明的wait()
调用的范围不一样,seelp()可以在任何需要的场景下调用,wait()必须使用在同步代码块
是否释放同步监视器的问题:如果两个方法都使用在同步代码块或者同步方法中,seelp()方法不会释放锁,而wait()会释放锁
线程通信应用
class Clerk{
private int productCount =0;
public void producProuluct() {
if(productCount<20){
productCount++;
System.out.println(Thread.currentThread().getName()+":开始生产"+productCount);
}
}
//消费
public void consumeProduct(){
if (productCount>0){
System.out.println(Thread.currentThread().getName()+":"+productCount);
productCount--;
}
}
}
class Producer extends Thread{//生产者
private Clerk clerk;
public Producer(Clerk clerk){
this.clerk= clerk;
}
@Override
public void run() {
System.out.println(getName()+":生成");
while (true){
clerk.producProuluct();
}
}
}
class Consumer extends Thread{
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk= clerk;
}
@Override
public void run() {
System.out.println(getName()+":消费");
while (true){
clerk.consumeProduct();
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
p1.setName("生产者1");
Consumer consumer = new Consumer(clerk);
consumer.setName("消费者");
p1.start();
consumer.start();
}
}
测试结果
生产者1:开始生产3
生产者1:开始生产1
生产者1:开始生产2
生产者1:开始生产3
生产者1:开始生产4
生产者1:开始生产5
生产者1:开始生产6
生产者1:开始生产7
生产者1:开始生产8
消费者:1
消费者:8
消费者:7
消费者:6
消费者:5
消费者:4
生产者1:开始生产9
生产者1:开始生产4
生产者1:开始生产5
生产者1:开始生产6
生产者1:开始生产7
生产者1:开始生产8
生产者1:开始生产9
生产者1:开始生产10
生产者1:开始生产11
生产者1:开始生产12
生产者1:开始生产13
消费者:3
消费者:13
生产者1:开始生产14
生产者1:开始生产14
生产者1:开始生产15
生产者1:开始生产16
生产者1:开始生产16
生产者1:开始生产17
生产者1:开始生产18
生产者1:开始生产19
生产者1:开始生产20
消费者:15
消费者:20
消费者:19
消费者:18
消费者:17
草都可以从石头缝隙中长出来更可况你呢

浙公网安备 33010602011771号