java juc1

一、volitale关键字

1. volitale可以保证线程共享数据的内存可见性,也就是说,数据被修改之后,其他线程读取该数据的时候,会直接从主内存里面读取,所以读取的是最新数据;

2.volitale的性能比加锁的性能高,相对于synchronized 是一种较为轻量级的同步策略;

3.缺陷

  a:volitale不能保证数据的"原子性";

  b:volitale 不能保证线程''互斥性'',也就是不能保证多个线程一次只能一个线程访问共享变量;

4.解决使用volatile时原子性问题,jdk1.5之后提供了java.util.concurrent.atomic包下提供了,常用原子变量:

a:volitale保证了内存可见性

b:CAS算法保证了原子性

CAS算法原理:在线程启动的时候,会读取一次共享变量标记为V,当此线程对该变量进行读写操作的时候,会进行再次读取标记为A,当且紧当V=A的时候,才会对变量进行更新操作。

 

二,CAS算法模拟

 

public class CAS {
    public static void main(String[] args) {
        final CompareAndSwap compareAndSwap = new CompareAndSwap();
        for (int a = 0; a < 10; a++) {
            new Thread(new Runnable() {
                public void run() {
                    int oldValue = compareAndSwap.getValue();
                        boolean aBoolean = compareAndSwap.compare(oldValue, (int) (Math.random()*101));
                    System.out.println(Math.random() * 101);
                        System.out.println(aBoolean);
                }
            }).start();
        }

    }
}
class CompareAndSwap {
    private  int value;

    public CompareAndSwap(int value) {
        this.value = value;
    }

    public CompareAndSwap() {
    }

    public synchronized int getValue() {
        return value;
    }

    public synchronized int setValue(int oldValue, int newValue) {
 
 
//getValue()为主内存的值,oldValue为预估值(第一次取得的值)

if (getValue() == oldValue) { oldValue = newValue; } return oldValue; }

public  synchronized boolean compare(int oldValue, int newValue){
    if (oldValue == setValue(oldValue, newValue)) {
        return true;
    }
    return false;
 }

}

 
三、锁分段机制

 

1,concurrentHashMap 采用了锁分段机制,允许多个线程并发访问,并且线程安全,所以效率较高。由于其底层也是通过加锁机制来保证线程安全,但是CAS是无锁操作,效率更高。所以,后来JVM也是采用CAS算法。

2,CopyOnWriteArraySet /CopyOnWriteArrayList:"写入并复制"

注意:添加操作多时,每次添加都会复制一次,开销比较大,迭代并发是适合选择;

 

四、闭锁CountDownLatch一个同步辅助类,当其他所有线程都执行结束以后,才会开始执行

 

public class TestCountDownLatch {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        OfCountDownLatch ofCountDownLatch = new OfCountDownLatch(countDownLatch);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5; i++) {
            new Thread(ofCountDownLatch).start();
        }
        try {
            countDownLatch.await();//等待其他方法执行结束
        } catch (InterruptedException e) {
        }
        long end = System.currentTimeMillis();
        System.out.println("五个线程耗时:"+(end - start));

    }

}
public class OfCountDownLatch implements Runnable{
    private CountDownLatch countDownLatch;

    public OfCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    public void run() {
        synchronized (this) {
            try {
                for (int i=0;i<50000;i++) {
                    if (i % 2 == 0) {
                        System.out.println(i);
                    }
                }
            }finally {
                countDownLatch.countDown();
            }
        }
    }
}

执行结果:

 

49992
49994
49996
49998

......

49992
49994
49996
49998

五个线程耗时:1104

 

五、callable接口

 

public class TestCallable {
    public static void main(String[] args) {
        CallableDemo callableDemo = new CallableDemo();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callableDemo);
        for (int i = 0; i < 10; i++) {
            new Thread(futureTask).start();
        }
        try {
            Integer result=futureTask.get();
            System.out.println(result);
            System.out.println("...................");//打印位置可以判断,callable接口也可以实现封闭锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
public class CallableDemo implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int a=0;a<=1000;a++) {
            if (a % 10 == 0) {
                sum+=a;
            }
        }
        return sum;
    }
}

结果:

 

50500
...................

 

六、同步锁

1、多线程安全解决方法:

 jdk1.5之前(synchronized隐式锁)

a、同步方法

b、同步代码块

2、jdk1.5之后使用同步锁

lock()上锁和unlock()释放锁

unlock()必须在finally使用来确保必须执行

 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by 13795 on 2017/9/18.
 */
public class LockTicket implements Runnable{
    static int ticket=100;
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }
        try {
            lock.lock();
            while (true) {
                if (ticket > 0) {

                    System.out.println(Thread.currentThread()+"当前余票为:"+ --ticket);
                }
            }
        }finally {
            lock.unlock();
        }

    }
}
public class LockTest {
    public static void main(String[] args) {

        LockTicket ticket=new LockTicket();

        new Thread(ticket,"一号窗口").start();
        new Thread(ticket,"二号窗口").start();
        new Thread(ticket,"三号窗口").start();
        new Thread(ticket,"四号窗口").start();
        new Thread(ticket,"五号窗口").start();
    }
}

结果:

 

Thread[一号窗口,5,main]当前余票为:100
........

Thread[一号窗口,5,main]当前余票为:6
Thread[一号窗口,5,main]当前余票为:5
Thread[一号窗口,5,main]当前余票为:4
Thread[一号窗口,5,main]当前余票为:3
Thread[一号窗口,5,main]当前余票为:2
Thread[一号窗口,5,main]当前余票为:1
Thread[一号窗口,5,main]当前余票为:0

 

七,虚假唤醒

线程通讯的时候,需要将wait放在循环里面,以防止虚假唤醒

 

  • A thread can also wake up without being notified, interrupted, or timing out, a so-calledspurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

         synchronized (obj) {
             while (<condition does not hold>)
                 obj.wait(timeout);
             ... // Perform action appropriate to condition
         }
    
public class TestOfProducterAndCustmer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producter pro = new Producter(clerk);
        Customer cus = new Customer(clerk);
        new Thread(pro,"生产者一").start();
        new Thread(pro,"生产者二").start();
        new Thread(cus,"消费者三").start();
        new Thread(cus, "消费者四").start();
    }
}
public class Clerk {
    private int count=0;

    /**
     * 生产者消费者
     */

    public synchronized void  get(){
        while (count >= 1){
            System.out.println("货满");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
            System.out.println(Thread.currentThread() + "生产后货品数量:" + ++count);
            this.notifyAll();
    }


    public synchronized void sall() {
        while (count <=0) {
            System.out.println("缺货");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread() + "消费后产品数量:" + --count);
        this.notifyAll();
    }

}
public class Customer implements Runnable {

    Clerk clerk = new Clerk();
    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sall();
        }
    }
}
public class Producter implements Runnable{
    Clerk clerk = new Clerk();

    public Producter(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }
        for (int i = 0; i < 20; i++) {
            clerk.get();
        }
    }
}

 

 

 

八,Condetion

使用Lock的时候可以使用需要使用Condetion进行线程通信,方法为

lock.newCondition()如下

 

 

private Condition condition = lock.newCondition();

Condetion有自己对应的线程通信方法 

1, condition.await();
2, condition.signal();
3,condition.signalAll();

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值