多线程之间通讯JDK1.5-Lock

synchronized:代码开始上锁,代码结束时释放锁;内置锁、自动化的、效率低、扩展性不高(不够灵活);

JDK1.5并发包Lock锁 --保证线程安全问题,属于手动挡,手动开始上锁,手动释放锁,灵活性高;

Lock 接口与 synchronized 关键字的区别

Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。

Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

Lock用法:

Lock写法
Lock lock  = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操作
}finally{
//一定在finally中释放锁
//也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
  lock.ublock();
}

 
class Res{
    public String username;
    public String sex;
    //true 生产者等待,消费者可消费 false生产者可以生产,消费者不可消费
    public boolean flag=false;
    Lock lock=new ReentrantLock();
}
class Out extends Thread{
    Res res;
    Condition newCondition;

    public Out(Res res,Condition newCondition){
        this.res=res;
        this.newCondition=newCondition;
    }
    @Override
    public void run() {
        //写操作
        int count=0;
        while (true){
            try{//防止异常后不释放锁
                res.lock.lock();
                if(res.flag){
                   newCondition.await();//让当前线程从运行变为阻塞,并且释放所的资源
                }
                if(count==0){//偶数
                    res.username="小明";
                    res.sex="男";
                } else {//奇数
                    res.username="小红";
                    res.sex="女";
                }
                count=(count+1)%2;
                res.flag=true;
                newCondition.signal();
            } catch (Exception e){
            } finally {
                res.lock.unlock();
            }
        }
    }
}
class Input extends Thread{
    Res res;
    Condition newCondition;
    public Input(Res res,Condition newCondition){
        this.res=res;
        this.newCondition=newCondition;
    }

    @Override
    public void run() {
        while (true){
            try{
                res.lock.lock();
                if(!res.flag){
                    newCondition.await();//让当前线程从运行变为阻塞,并且释放所的资源
                }
                System.out.println(res.username+","+res.sex);
                res.flag=false;
                newCondition.signal();
            } catch (Exception e){
            } finally {
                res.lock.unlock();
            }
        }
    }
}
public class LockDemo {
    public static void main(String[] args) {
        Res res = new Res();
        Condition condition=res.lock.newCondition();
        Out out = new Out(res,condition);
        Input input = new Input(res,condition);
        out.start();
        input.start();
    }

}

 

 

Condition用法:

Condition condition = lock.newCondition();
res. condition.await();  类似wait
res. Condition. Signal() 类似notify

多线程并发(Thread)操作同一个资源---------网站并发(多个请求同时访问一台服务)

停止线程

 

停止线程思路

 

   1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

 

    2.  使用stop方法强行终止线程;这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果(没执行完就终止没有记录上次执行点,并且不可恢复,不论你当前什么状况都给你停掉)。

 

    3.  使用interrupt方法中断线程。

那么怎么停止线程比较合适呢?或者说怎么设计一种停止线程的方式?

class StopThreadDemo extends Thread{
    private volatile boolean flag=true;

    @Override
    public void run() {
        System.out.println("子线程开始执行......");
        while (flag){

        }
        System.out.println("子线程执行结束......");
    }
    public void stopThread(){
        this.flag=false;
    }
}
public class StopThread {
    public static void main(String[] args) throws InterruptedException {
        StopThreadDemo stopThreadDemo=new StopThreadDemo();
        stopThreadDemo.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("我是主线程,i:"+i);
            Thread.sleep(1000);
            if(i==6)
                stopThreadDemo.stopThread();
        }
    }
}

我是主线程,i:0
子线程开始执行......
我是主线程,i:1
我是主线程,i:2
我是主线程,i:3
我是主线程,i:4
我是主线程,i:5
我是主线程,i:6
我是主线程,i:7
子线程执行结束......
我是主线程,i:8
我是主线程,i:9


 
class StopThreadDemo extends Thread{
    private volatile boolean flag=true;

    @Override
    public synchronized void run() {
        System.out.println("子线程开始执行......");
        while (flag){
            try {
                wait();
            } catch (InterruptedException e) {
//                e.printStackTrace();
                stopThread();
            }
        }
        System.out.println("子线程执行结束......");
    }
    public void stopThread(){
        this.flag=false;
    }
}
public class StopThread {
    public static void main(String[] args) throws InterruptedException {
        StopThreadDemo stopThreadDemo=new StopThreadDemo();
        stopThreadDemo.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("我是主线程,i:"+i);
            Thread.sleep(1000);
            if(i==6) {
                //当前等待线程直接抛出异常
                stopThreadDemo.interrupt();
//                stopThreadDemo.stopThread();
            }
        }
    }
}
以上两种方式都可以。。。

可以看到这是一种停止线程的方式

 

ThreadLocal

ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。

线程1和线程2各自操作自己的副本count,互相影响。

 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

 

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

  • void set(Object value)设置当前线程的线程局部变量的值。
  • public Object get()该方法返回当前线程所对应的线程局部变量。
  • public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
  • protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

案例:创建三个线程,每个线程生成自己独立序列号。

class ResNum{
    public int count=0;
    public static ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
        protected Integer initialValue(){
            return 0;
        }
    };

    public String getNumber(){
        count=threadLocal.get()+1;
        threadLocal.set(count);
//        count=count+1;
        return count+"";
    }
}
class LocalThreadDemo extends Thread{
    private ResNum resNum;
    public LocalThreadDemo(ResNum resNum){
        this.resNum=resNum;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(getName()+","+resNum.getNumber());
        }
    }
}
public class ThreadLocalDemo {
    public static void main(String[] args) {
        ResNum resNum1=new ResNum();
//        ResNum resNum2=new ResNum();
//        ResNum resNum3=new ResNum();
        LocalThreadDemo t1=new LocalThreadDemo(resNum1);
        LocalThreadDemo t2=new LocalThreadDemo(resNum1);
        LocalThreadDemo t3=new LocalThreadDemo(resNum1);
        t1.start();
        t2.start();
        t3.start();
    }
}

 

posted @ 2018-07-24 04:33  LoseMyFuture  阅读(144)  评论(0编辑  收藏  举报