Java线程2

Lock锁:

ReentrantLock实现了Lock接口,所以可以称为Lock锁

ReentrantLock与synchronized的区别:

1、实现原理不同:ReentrantLock是一种代码层面的控制实现,而synchronized是关键字,依靠的是底层编译后的指令实现

2、加锁范围不同:ReentrantLock只能对某一段代码块加锁,而synchronized可以对代码块和方法加锁

3、加锁释放锁方式不同:ReentrantLock需要手动的加锁释放锁,而synchronized是隐式的自动的加锁,自动释放锁(代码执行完了,出现异常了)

示例:模拟售票(使用Lock锁)

public class TicketThread extends  Thread{

    static int num = 100;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while(true){
            /*
              使用try{}finally{}的原因:
                 Lock锁是手动添加及释放的,如果加锁后的代码出现异常,就不会释放锁。
                 使用try{}finally{}之后,将释放锁的代码放入finally{}的代码块中,不管try{}代码块中是否出现异常都会释放锁。
            */
            try{
                lock.lock();//加锁
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                }else{
                    break;
                }
            }finally {
                lock.unlock();//释放锁
            }
        }
    }
}

线程死锁:

不同的线程分别占有对方需要的同步资源不放,双方相互等待,程序不会报错,一直卡着。

eg:自己制造一个线程死锁,但是不确保一定能死锁,因为线程的调用由系统绝对。

public class DieLockThread extends Thread{

    static Object objA = new Object();
    static Object objB = new Object();
    boolean flag;


    public DieLockThread(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (objA){
                System.out.println("if objA");
                synchronized (objB){
                    System.out.println("if objB");
                }
            }
        }else{
            synchronized (objB){
                System.out.println("else objB");
                synchronized (objA){
                    System.out.println("else objA");
                }
            }
        }
    }
}

public class Test {

    public static void main(String[] args) {

        DieLockThread t1 = new DieLockThread(true);
        t1.start();
        DieLockThread t2 = new DieLockThread(false);
        t2.start();
    }
}

线程通信:

会使用到三个方法:

wait();是Object类中定义的方法,必须是使用同步对象来调用,让线程等待,释放锁,等待的线程不能自己醒来,必须让其他线程唤醒

notify();是Object类中定义的方法,必须是使用同步对象来调用,唤醒等待的线程

notifyAll();是Object类中定义的方法,必须是使用同步对象来调用,用来唤醒所有被等待的线程

三个方法都必须在同步代码块中执行。

示例1:两个线程交替打印1-100的数字

public class PrintNumThread extends Thread{


    static int num = 1;
    static  Object object = new Object();
    @Override
    public void run() {
        while(num<=100){
            synchronized(object){
                object.notify();//唤醒等待的线程
                System.out.println(Thread.currentThread().getName()+":"+num);
                num++;
                try {
                    if(num<=100){
                        object.wait();//让线程等待,释放锁,等待的线程不能自己醒来,必须让其他线程唤醒
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class Test {


    public static void main(String[] args) {


        PrintNumThread p1 = new PrintNumThread();
        p1.start();

        PrintNumThread p2 = new PrintNumThread();
        p2.start();
    }
}

sleep()和wait()的共同点与区别:

共同点:都可以让线程进入阻塞状态

区别:sleep();让线程阻塞指定的时间,时间到了后,自己唤醒进入到就绪状态,不会释放同步锁,是Thread类中的方法。

​ wait();让线程进入等待(阻塞),不会自己唤醒,必须通过notify()、notifiAll()唤醒,等待时,会释放同步锁,是Object类中的方法。

示例2:生产者与消费者问题

生产者(Productor)将产品放在柜台(Counter),而消费者(Customer)从柜台 处取走产品,生产者一次只能生产固定数量的产品(比如:1), 这时柜台中不能 再放产品,此时生产者应停止生产等待消费者拿走产品,此时生产者唤醒消费者来 取走产品,消费者拿走产品后,唤醒生产者,消费者开始等待.

public class Counter {
    int num = 0;//共享商品数量
    
    /*
      生产者生产商品
     */
    public synchronized void add(){

        if(num==0){
            this.num=1;
            this.notify();//唤醒消费者
            System.out.println("生产者生产了1件商品");
        }else{
            try {
                this.wait();//生产者等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /*
       消费者取走商品
     */
    public synchronized void sub(){

        if(num>0){
            this.num=0;
            this.notify();//唤醒生产者
            System.out.println("消费者取走了1件商品");
        }else {
            try {
                this.wait();//消费者等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Productor extends Thread {
    /*
      生产者线程
     */
    Counter counter ;

    public Productor(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.add();
        }
    }
}

public class Customer extends Thread{

    /*
      消费者线程
     */
    Counter counter ;

    public Customer(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.sub();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Productor p = new Productor(counter);
        Customer c = new Customer(counter);
        p.start();
        c.start();
    }
}

创建线程的第三种方法:

实现Callable接口

由于创建线程时,需要添加实现Runnable接口的任务,Callable接口没有实现Runnable接口,不能直接创建线程,所以需要用FutureTask来接收任务,FutureTask实现了Runnable接口,因此可以间接用来创建线程。

import java.util.concurrent.Callable;

public class SumTask implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int num = 0;
        for (int i = 0; i < 10; i++) {
            num += i ;
        }
        return num;
    }
}

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test {

    public static void main(String[] args) {

        SumTask sumTask = new SumTask();//创建任务
        FutureTask<Integer> futureTask = new FutureTask(sumTask);//接收任务
        Thread thread = new Thread(futureTask);//创建线程
        thread.start();//启动线程
        try {
            Integer integer = futureTask.get();//获取线程call()的返回值
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值